#JCConf
Event Sourcing with Reactor
and Spring Statemachine
Jimmy Lu
jilu@digitalriver.com
Digital River, Inc.
Agenda
• Event Sourcing
• Reactor
• Spring Statemahcine
• Demo of Event Sourcing with Reactor
and Spring Statemachine
• Summary
Event Sourcing
• All changes to application state are
stored as a sequence of events
• Not only manage current state
• Replays sequence of events to
reconstruct application state
• Natively support audit trail
• Eventually consistent
• Commonly works with CQRS pattern
https://msdn.microsoft.com/en-us/library/dn589792.aspx
Event Store
• Append-only store (events are
immutable)
• Series immutable events
• compensating event
• Acts as the source of truth of
materialised view
• Simple schema for storing event
• Behaves like a database with message
broker characteristics
Event Store
• Better work with version data format
• Consider creating snapshots at specific
intervals if event stream is too large
• Consumers of the events must be
idempotent
• Event ID typically maps to individual
entities
• The order of the event is important
Event store
https://geteventstore.com/
Benefits of Event Sourcing
• A solution to ensure atomicity when
mutating entity states while publishing
events simultaneously
• 100% accurate audit logging which is not
an afterthought
• Easy temporal queries
• Single event centric model
• Conflict management
• Simplified/Better testing
A Taste of Event Sourcing
• // Akka Persistence
• public void onReceiveRecover(Object msg) {
• if (msg instanceof Evt) {
• state.update((Evt) msg);
• } else if (msg instanceof SnapshotOffer) {
• state = (ExampleState)((SnapshotOffer)msg).snapshot();
• } else {
• unhandled(msg);
• }
• }
http://doc.akka.io/docs/akka/snapshot/java/persistence.html#Event_sourcing
• // Akka Persistence
• public void onReceiveCommand(Object msg) {
• if (msg instanceof Cmd) {
• final String data = ((Cmd)msg).getData();
• final Evt evt1 = new Evt(data + "-" + getNumEvents());
• final Evt evt2 = new Evt(data + "-" + (getNumEvents() + 1));
• persistAll(asList(evt1, evt2), new Procedure<Evt>() {
• public void apply(Evt evt) throws Exception {
• state.update(evt);
• if (evt.equals(evt2)) {
• getContext().system().eventStream().publish(evt);
• }
• }
• });
• } else if (msg.equals("snap")) {
• saveSnapshot(state.copy());
• }
• ......
• }
http://doc.akka.io/docs/akka/snapshot/java/persistence.html#Event_sourcing
• public class Account {
• ......
•
• public List<Event> process(OpenAccountCommand cmd) {
• return EventUtil.events(new AccountOpenedEvent(cmd.getInitialBalance()));
• }
•
• public List<Event> process(CreditAccountCommand cmd) {
• return EventUtil.events(new AccountCreditedEvent(cmd.getAmount(), cmd.getTransactio
nId()));
• }
•
• public void apply(AccountOpenedEvent event) {
• balance = event.getInitialBalance();
• }
•
• public void apply(AccountDebitedEvent event) {
• balance = balance.subtract(event.getAmount());
• }
•
• public void apply(AccountCreditedEvent event) {
• balance = balance.add(event.getAmount());
• }
• }
https://github.com/cer/event-sourcing-examples
Reactor
• A foundational library for building reactive
fast-data applications on the JVM
• An implementation of the Reactive Streams
Specification
• Building on top of the Disruptor RingBuffer
• Functional and reactive to allow for easy
composition of operations
• 10’s of millions of operations per second
(even up to 100’s if you have enough
hardware horsepower)
Snippet of Reactor
• static {
• // Only done once, statically, and shared across this classloader
• Environment.initialize();
• }
• // Create a Stream subclass we can sink values into
• Broadcaster<String> b = Broadcaster.create();
• b
• // dispatch onto a Thread other than 'main'
• .dispatchOn(Environment.cachedDispatcher())
• // transform input to UC
• .map(String::toUpperCase)
• // only let certain values pass through
• .filter(s -> s.startsWith("HELLO"))
• // produce demand
• .consume(s -> System.out.println(Thread.currentThread() + ": " + s));
• // Sink values into this Broadcaster
• b.onNext("Hello World!");
• // This won't print
• b.onNext("Goodbye World!");
• // Must wait for tasks in other threads to complete
• Thread.sleep(500);
http://projectreactor.io/
Reactor Modules
• reactor-core
• reactor-stream
• reactor-bus
• reactor-net
http://projectreactor.io/docs/reference/
reactor-core
http://projectreactor.io/docs/reference/
reactor-stream
http://projectreactor.io/docs/reference/
reactor-bus
http://projectreactor.io/docs/reference/
reactor-net
http://projectreactor.io/docs/reference/
What/Why State Machine
• Application is and may exist in a finite
number of states and then something
happens which takes your application
from one state to the next.
• What will drive a state machine are
triggers which are either based on
events or timers.
• Behavior is always guaranteed to be
consistent
• Easily debugged due to ways how
operational rules are written in stone
Spring Statemachine (SSM)
• Easy to use flat one level state machine for
simple use cases.
• Hierarchical state machine structure to
ease complex state configuration.
• State machine regions to provide even
more complex state configurations.
• Usage of triggers, transitions, guards and
actions.
• Distributed state machine based on a
Zookeeper
• State machine event listeners.
Abstractions Provided by SSM
• States
• Hierarchical
States
• Regions
• Transitions
• Guards
• Actions
• Pseudo States
– Initial State
– Terminate State
– History State
– Choice State
– Fork State
– Join State
• Distributed States
Turnstile
http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
Turnstile Code Sample
• public enum States {
• LOCKED, UNLOCKED
• }
•
• public enum Events {
• COIN, PUSH
• }
• public void configure(StateMachineStateConfigurer<States, Events> states) thro
ws Exception {
• states.withStates()
• .initial(States.LOCKED)
• .states(EnumSet.allOf(States.class));
• }
http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
Turnstile Code Sample
• public void configure(StateMachineTransitionConfigurer<States, Events> tra
nsitions) throws Exception {
• transitions
• .withExternal()
• .source(States.LOCKED)
• .target(States.UNLOCKED)
• .event(Events.COIN)
• .and()
• .withExternal()
• .source(States.UNLOCKED)
• .target(States.LOCKED)
• .event(Events.PUSH);
• }
http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
Washer
http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
Washer Code Sample
• public void configure(StateMachineStateConfigurer<States, Events> states)
throws Exception {
• states
• .withStates()
• .initial(States.RUNNING)
• .state(States.POWEROFF)
• .end(States.END)
• .and()
• .withStates()
• .parent(States.RUNNING)
• .initial(States.WASHING)
• .state(States.RINSING)
• .state(States.DRYING)
• .history(States.HISTORY, History.SHALLOW);
• }
http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
Building Event Sourced
Applications
• The states (finite, normally represented
by enumeration) of a domain object are
maintained by spring state machine
• Pub/Sub events by reactor-bus within
the application
• Event stream could be mapped to
reactor-stream with reactive streams
support
• Distributed state could be used to
enforce strong consistency of domain
objects
Some Thoughts About The
Idea
• Why not existing frameworks?
• Lighter-weight state machine?
• Lookup API for a state machine?
– State nextState = statemahcine.lookup(currentState, event);
• Distributed state or not?
• https://github.com/spring-
projects/spring-statemachine/issues/7
• Choice of event store? Kafka?
Cassandra?
Reference
• Event Sourcing by Martin Fowler
• Event Sourcing Basics
• Developing event-driven microservices
with event sourcing and CQRS
• https://github.com/cer/event-sourcing-
examples/wiki
• Akka Persistence Documentation
• Spring Statemachine Documentation
• Reactor Documentation

Event sourcing with reactor and spring statemachine

  • 1.
    #JCConf Event Sourcing withReactor and Spring Statemachine Jimmy Lu jilu@digitalriver.com Digital River, Inc.
  • 2.
    Agenda • Event Sourcing •Reactor • Spring Statemahcine • Demo of Event Sourcing with Reactor and Spring Statemachine • Summary
  • 3.
    Event Sourcing • Allchanges to application state are stored as a sequence of events • Not only manage current state • Replays sequence of events to reconstruct application state • Natively support audit trail • Eventually consistent • Commonly works with CQRS pattern
  • 4.
  • 5.
    Event Store • Append-onlystore (events are immutable) • Series immutable events • compensating event • Acts as the source of truth of materialised view • Simple schema for storing event • Behaves like a database with message broker characteristics
  • 6.
    Event Store • Betterwork with version data format • Consider creating snapshots at specific intervals if event stream is too large • Consumers of the events must be idempotent • Event ID typically maps to individual entities • The order of the event is important
  • 7.
  • 8.
    Benefits of EventSourcing • A solution to ensure atomicity when mutating entity states while publishing events simultaneously • 100% accurate audit logging which is not an afterthought • Easy temporal queries • Single event centric model • Conflict management • Simplified/Better testing
  • 9.
    A Taste ofEvent Sourcing • // Akka Persistence • public void onReceiveRecover(Object msg) { • if (msg instanceof Evt) { • state.update((Evt) msg); • } else if (msg instanceof SnapshotOffer) { • state = (ExampleState)((SnapshotOffer)msg).snapshot(); • } else { • unhandled(msg); • } • } http://doc.akka.io/docs/akka/snapshot/java/persistence.html#Event_sourcing
  • 10.
    • // AkkaPersistence • public void onReceiveCommand(Object msg) { • if (msg instanceof Cmd) { • final String data = ((Cmd)msg).getData(); • final Evt evt1 = new Evt(data + "-" + getNumEvents()); • final Evt evt2 = new Evt(data + "-" + (getNumEvents() + 1)); • persistAll(asList(evt1, evt2), new Procedure<Evt>() { • public void apply(Evt evt) throws Exception { • state.update(evt); • if (evt.equals(evt2)) { • getContext().system().eventStream().publish(evt); • } • } • }); • } else if (msg.equals("snap")) { • saveSnapshot(state.copy()); • } • ...... • } http://doc.akka.io/docs/akka/snapshot/java/persistence.html#Event_sourcing
  • 11.
    • public classAccount { • ...... • • public List<Event> process(OpenAccountCommand cmd) { • return EventUtil.events(new AccountOpenedEvent(cmd.getInitialBalance())); • } • • public List<Event> process(CreditAccountCommand cmd) { • return EventUtil.events(new AccountCreditedEvent(cmd.getAmount(), cmd.getTransactio nId())); • } • • public void apply(AccountOpenedEvent event) { • balance = event.getInitialBalance(); • } • • public void apply(AccountDebitedEvent event) { • balance = balance.subtract(event.getAmount()); • } • • public void apply(AccountCreditedEvent event) { • balance = balance.add(event.getAmount()); • } • } https://github.com/cer/event-sourcing-examples
  • 12.
    Reactor • A foundationallibrary for building reactive fast-data applications on the JVM • An implementation of the Reactive Streams Specification • Building on top of the Disruptor RingBuffer • Functional and reactive to allow for easy composition of operations • 10’s of millions of operations per second (even up to 100’s if you have enough hardware horsepower)
  • 13.
    Snippet of Reactor •static { • // Only done once, statically, and shared across this classloader • Environment.initialize(); • } • // Create a Stream subclass we can sink values into • Broadcaster<String> b = Broadcaster.create(); • b • // dispatch onto a Thread other than 'main' • .dispatchOn(Environment.cachedDispatcher()) • // transform input to UC • .map(String::toUpperCase) • // only let certain values pass through • .filter(s -> s.startsWith("HELLO")) • // produce demand • .consume(s -> System.out.println(Thread.currentThread() + ": " + s)); • // Sink values into this Broadcaster • b.onNext("Hello World!"); • // This won't print • b.onNext("Goodbye World!"); • // Must wait for tasks in other threads to complete • Thread.sleep(500); http://projectreactor.io/
  • 14.
    Reactor Modules • reactor-core •reactor-stream • reactor-bus • reactor-net
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
    What/Why State Machine •Application is and may exist in a finite number of states and then something happens which takes your application from one state to the next. • What will drive a state machine are triggers which are either based on events or timers. • Behavior is always guaranteed to be consistent • Easily debugged due to ways how operational rules are written in stone
  • 21.
    Spring Statemachine (SSM) •Easy to use flat one level state machine for simple use cases. • Hierarchical state machine structure to ease complex state configuration. • State machine regions to provide even more complex state configurations. • Usage of triggers, transitions, guards and actions. • Distributed state machine based on a Zookeeper • State machine event listeners.
  • 22.
    Abstractions Provided bySSM • States • Hierarchical States • Regions • Transitions • Guards • Actions • Pseudo States – Initial State – Terminate State – History State – Choice State – Fork State – Join State • Distributed States
  • 23.
  • 24.
    Turnstile Code Sample •public enum States { • LOCKED, UNLOCKED • } • • public enum Events { • COIN, PUSH • } • public void configure(StateMachineStateConfigurer<States, Events> states) thro ws Exception { • states.withStates() • .initial(States.LOCKED) • .states(EnumSet.allOf(States.class)); • } http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
  • 25.
    Turnstile Code Sample •public void configure(StateMachineTransitionConfigurer<States, Events> tra nsitions) throws Exception { • transitions • .withExternal() • .source(States.LOCKED) • .target(States.UNLOCKED) • .event(Events.COIN) • .and() • .withExternal() • .source(States.UNLOCKED) • .target(States.LOCKED) • .event(Events.PUSH); • } http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
  • 26.
  • 27.
    Washer Code Sample •public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception { • states • .withStates() • .initial(States.RUNNING) • .state(States.POWEROFF) • .end(States.END) • .and() • .withStates() • .parent(States.RUNNING) • .initial(States.WASHING) • .state(States.RINSING) • .state(States.DRYING) • .history(States.HISTORY, History.SHALLOW); • } http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/
  • 28.
    Building Event Sourced Applications •The states (finite, normally represented by enumeration) of a domain object are maintained by spring state machine • Pub/Sub events by reactor-bus within the application • Event stream could be mapped to reactor-stream with reactive streams support • Distributed state could be used to enforce strong consistency of domain objects
  • 29.
    Some Thoughts AboutThe Idea • Why not existing frameworks? • Lighter-weight state machine? • Lookup API for a state machine? – State nextState = statemahcine.lookup(currentState, event); • Distributed state or not? • https://github.com/spring- projects/spring-statemachine/issues/7 • Choice of event store? Kafka? Cassandra?
  • 30.
    Reference • Event Sourcingby Martin Fowler • Event Sourcing Basics • Developing event-driven microservices with event sourcing and CQRS • https://github.com/cer/event-sourcing- examples/wiki • Akka Persistence Documentation • Spring Statemachine Documentation • Reactor Documentation