30
#JCConf Event Sourcing with Reactor and Spring Statemachine Jimmy Lu [email protected] Digital River, Inc.

Event sourcing with reactor and spring statemachine

Embed Size (px)

Citation preview

Page 1: Event sourcing with reactor and spring statemachine

#JCConf

Event Sourcing with Reactor and Spring

StatemachineJimmy Lu

[email protected] River, Inc.

Page 2: Event sourcing with reactor and spring statemachine

Agenda• Event Sourcing• Reactor• Spring Statemahcine• Demo of Event Sourcing with Reactor

and Spring Statemachine• Summary

Page 3: Event sourcing with reactor and spring statemachine

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

Page 4: Event sourcing with reactor and spring statemachine

https://msdn.microsoft.com/en-us/library/dn589792.aspx

Page 5: Event sourcing with reactor and spring statemachine

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

Page 6: Event sourcing with reactor and spring statemachine

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

Page 7: Event sourcing with reactor and spring statemachine

Event store

https://geteventstore.com/

Page 8: Event sourcing with reactor and spring statemachine

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

Page 9: Event sourcing with reactor and spring statemachine

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

Page 10: Event sourcing with reactor and spring statemachine

• // 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

Page 11: Event sourcing with reactor and spring statemachine

• 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.getTransacti

onId())); •   }• •   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

Page 12: Event sourcing with reactor and spring statemachine

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)

Page 13: Event sourcing with reactor and spring statemachine

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/

Page 14: Event sourcing with reactor and spring statemachine

Reactor Modules• reactor-core• reactor-stream• reactor-bus• reactor-net

Page 15: Event sourcing with reactor and spring statemachine

http://projectreactor.io/docs/reference/

Page 16: Event sourcing with reactor and spring statemachine

reactor-core

http://projectreactor.io/docs/reference/

Page 17: Event sourcing with reactor and spring statemachine

reactor-stream

http://projectreactor.io/docs/reference/

Page 18: Event sourcing with reactor and spring statemachine

reactor-bus

http://projectreactor.io/docs/reference/

Page 19: Event sourcing with reactor and spring statemachine

reactor-net

http://projectreactor.io/docs/reference/

Page 20: Event sourcing with reactor and spring statemachine

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

Page 21: Event sourcing with reactor and spring statemachine

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.

Page 22: Event sourcing with reactor and spring statemachine

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

Page 23: Event sourcing with reactor and spring statemachine

Turnstile

http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/

Page 24: Event sourcing with reactor and spring statemachine

Turnstile Code Sample• public enum States { •     LOCKED, UNLOCKED • }• • public enum Events { •     COIN, PUSH • }

• public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {

•     states.withStates() •         .initial(States.LOCKED) •         .states(EnumSet.allOf(States.class)); • }

http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/

Page 25: Event sourcing with reactor and spring statemachine

Turnstile Code Sample• public void configure(StateMachineTransitionConfigurer<States, Ev

ents> transitions) 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/

Page 26: Event sourcing with reactor and spring statemachine

Washer

http://docs.spring.io/spring-statemachine/docs/current/reference/htmlsingle/

Page 27: Event sourcing with reactor and spring statemachine

Washer Code Sample• public void configure(StateMachineStateConfigurer<States, Events> st

ates) 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/

Page 28: Event sourcing with reactor and spring statemachine

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

Page 29: Event sourcing with reactor and spring statemachine

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/sp

ring-statemachine/issues/7• Choice of event store? Kafka?

Cassandra?