Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Event Sourcing with ESE

Event Sourcing with ESE

ESE stands for Event Sourced Entities, and is part of project Goodees, which is a collection of Java EE utilities.

We started ESE since we missed a programming model that integrates well with Java EE and offers entities with event sourced state and also serve for executing business methods. Think of it as "What if Entity EJBs were event sourced rather than ORM?"

Avatar for Patrik Duditš

Patrik Duditš

December 12, 2017
Tweet

More Decks by Patrik Duditš

Other Decks in Technology

Transcript

  1. Part of Goodees project • Utility classes for Java EE

    • https://github.com/goodees/goodees • Event Sourced Entities
  2. Buzzword bingo sheet Aggregate root Bounded Context Sharding CQRS Asynchronous

    Actor model Microservices Resilient Kafka Cloud native Scalable Schemaless Reactive Message passing Event store Event storming Replication Domain Driven Process manager Distributed High availability Lock-free CQS Eventual Consistency Stream processing
  3. The idea of event sourcing You only store facts about

    past events. State can be reconstructed by replaying these events in order. All state in your application is transient. Wish List Bounded Context: Wish registered Parent registered Wish content changed Parent verified Gift bought Child registered Wish deleted
  4. Wish List Bounded Context: Wish registered Parent registered Wish content

    changed Parent verified Gift bought Child registered Wish deleted Q?
  5. Java Frameworks for event sourcing • Akka, Lagom • Axon

    Framework • Es4j • ESE – Event sourced Entities
  6. Motivation We are aware of “Not invented here syndrome”, but

    we use our own, better fitting term for it.
  7. Protocol Gateway Metrics & Alerting Charging & Roaming Mass Configuration

    Billing Charge Session Management Mobile app B2B APIs Roaming platforms SAP Electricity grid ~ 40 commands ~ 40 interfaces
  8. Problems we faced • State of station scattered across subsystems

    • Implementation details of station protocols as well • Concurrent communication exchanges towards/from stations • Constructs similar to synchronize(station) {} • State synchronization in high availability setups
  9. Features of ESE • Java 8 SE – few dependencies

    (slf4j, jackson) • Straight API – No annotations or reflection • Lock-free concurrency • Support for JSON serialization of events • Support for storing events via JDBC • Multiple execution modes (sync, async)
  10. ESE Building blocks - Concepts Runtime • Access point for

    passing a request to specific entity • Integration with surrounding environment • Singleton Entity • Stateful object with an ID • Executes requests • Performs business logic • Not JPA entity • State built exclusively by applying events
  11. ESE Building blocks - APIs Dispatcher • Guarantees one request

    per entity handled • Executes requests on a thread pool • Takes care of timeouts and retries Event sourcing APIs • API for entity lifecycle • Events • Persisting and application of events
  12. Execution within entity "Jane wants a 100€ lego" @state: Is

    Jane registered in this wishlist? @behavior service: Was she obeyant enough?
  13. How ESE make this easy? • Handles lifecycle of the

    entity • Entity instantiation • Initial replay of events • Initialization of entity • Handles request dispatching • Handles version of the entity and events • Every event increments version of the entity by one • Handles retries in case of errors • By default, every request is tried 5 times before it fails • Handles exceptions in all of the handling • Exceptions due to optimistic locks, execution of side effects, JSON serialization, …
  14. The two building blocks Runtime class • Extends SomeEventSourcingRuntime •

    Singleton per entity type • Determines • request dispatch • entity lifecycle • event storage • request retries Entity class • Extends SomeEntity • One instance per id: String • Handles requests • Stores events • Builds state • Performs side effects
  15. Entity initialization • If entity is not in memory, instantiate

    it, pass it dependencies • Replay all its events • (optimization possible with snapshots) • Invoke appropriate execution method * The things in italics is what you need to code
  16. Dispatch support WishlistEntity extends AsyncEntity SyncEntity ProxiedSyncEntity<Wishlist> Request representation class

    VerifyParent implements Request<Parent> { String verificationToken(); } interface WishList { Parent verifyParent( String token); } Client interface parent = wishlists .execute(id, new VerifyParent( token)) .get() parent = wishlists .execute(id, new VerifyParent( token)) .get() parent = wishlists .execute(id) .verifyParent(token) Entity interface CompletableFuture<RS> execute( Request<RS> request) RS execute( Request<RS> request) WishList requestHandler() Runtime extends AsyncEventSourcingRuntime <WishlistEntity> SyncEventSourcingRuntime <WishlistEntity> ProxiedSyncEventSourcingRun- time<WishlistEntity,Wishlist>
  17. Dispatch support • Utility classes for matching Request types to

    methods • Until pattern matching in Java 11… requestHandler = SyncRequestHandler.withDefaultFallback() .on(AddItem.class, this::addItem) .on(AdjustItemAmount.class, this::adjustItem) .on(RemoveItem.class, this::removeItem) .on(StartCheckout.class, this::startCheckout) .build(); requestHandler.handle(request); private OrderTotal addItem(AddItem request) { …
  18. Events • Event consists of • Event type • Entity

    id • Entity version • Event timestamp • Payload attributes • Conveniently created with Immutables • https://immutables.github.io • Events are your API now. Evolve them carefully. @Value.Immutable public interface ParentRegisteredEvent extends GiftEvent { String id(); String name(); String email(); static Builder builder(EventSourcedEntity entity) { return new Builder().from(entity); } class Builder extends ImmutableParentRegisteredEvent.Builder implements FromEntity<Builder> { } }
  19. Update state updateState(Event event) Similar helper methods for matching event

    types private TypeSwitch eventHandler = TypeSwitch.builder() .on(ParentRegisteredEvent.class, this::onParentRegistered) .on(ParentVerifiedEvent.class, this::onParentVerified) .build(); private Map<String, Parent> unverifiedParents = new HashMap<>(); void updateState(Event event) { eventHandler.executeMatching(event); } private void onParentRegistered(ParentRegisteredEvent event) { unverifiedParents.put(event.id(), Parent.of(ParentId.of(event.id()), event.name(), event.email())); }
  20. Side effects You can perform side effects in your execute

    method, after persistAndUpdate finishes. performPostInvokeActions(List<Event> events, Throwable t) Fire and forget request-independent actions - no compensation possible here.
  21. How to start <dependency> <groupId>io.github.goodees</groupId> <artifactId>ese-core</artifactId> <version>0.1</version> </dependency> <dependency> <groupId>org.immutables</groupId>

    <artifactId>value</artifactId> <version>2.5.6</version> <scope>provided</scope> </dependency> https://github.com/goodees/ese-example-gifts https://goodees.github.io/goodees/ese/apidocs/
  22. Roadmap to 1.0 • Website • Full example • More

    convenient configuration of runtime • Support for building projections
  23. Recap • The state is built from facts – past

    events • Every entity in ESE is a stateful object that performs business logic • Runtime is singleton that handles dispatch and configuration of environment • ESE gives you simple API for all of that Q?
  24. Buzzword bingo score? Aggregate root Bounded Context Sharding CQRS Asynchronous

    Actor model Microservices Resilient Kafka Cloud native Scalable Schemaless Reactive Message passing Event store Event storming Replication Domain Driven Process manager Distributed High availability Lock-free CQS Eventual Consistency Stream processing