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

The Building Blocks of an Event Driven CQRS Application in Scala

The Building Blocks of an Event Driven CQRS Application in Scala

In this talk we will have a look at the basic building blocks we need when developing an Event Driven CQRS application in Scala.

We will discuss some design choices and challenges we may encounter and how to tackle them using the Scala Type System and some functional programming techniques.

We'll explore the following topics:

- Defining an Aggregate and its Protocol (Commands and Events) in the form of case classes (obviously!);

- Using Future and Try to express computations;

- Implementing an Aggregate by means of BehaviorDsl based on its Protocol and PartialFunctions;

- How to glue them all together to produce a write and a read model;

Finally, we will have a look on how to integrate it with Akka and Akka Persistence.

Renato Cavalcanti

September 25, 2015
Tweet

More Decks by Renato Cavalcanti

Other Decks in Technology

Transcript

  1. Agenda DDD / CQRS / Event Sourcing Aggregates / Commands

    / Events in Scala Akka and asynchrounous programming Akka Persistence and Event Sourcing
  2. DDD / CQRS / ES Aggregate is a DDD concept.

    It has a root and zero or more entities and value objects underneath Commands and Events are used in CQRS Events can be persisted and replayed
  3. Event Driven / Sourcing CQRS is Event Driven, but not

    necessarily implements Event Sourcing in synchronous CQRS: tx(Cmd ⇒ Aggregate ⇒ Event ⇒ View) in asynchronous CQRS: tx(Cmd ⇒ Aggregate ⇒ Event) tx(Event ⇒ View)
  4. Scala And CQRS On creation C m d = >

    E v e n t E v e n t = > A g g r e g a t e / / t h e r e f o r e w e h a v e C m d = > ( A g g r e g a t e , E v e n t ) Post-creation ( A g g r e g a t e , C m d ) = > S e q [ E v e n t ] ( A g g r e g a t e , E v e n t ) = > A g g r e g a t e / / t h e r e f o r e w e h a v e ( A g g r e g a t e , C m d ) = > ( A g g r e g a t e , S e q [ E v e n t ] )
  5. Async API On creation C m d = > F

    u t u r e [ E v e n t ] E v e n t = > A g g r e g a t e / / t h e r e f o r e w e h a v e C m d = > F u t u r e [ ( A g g r e g a t e , E v e n t ) ] Post-creation ( A g g r e g a t e , C m d ) = > F u t u r e [ S e q [ E v e n t ] ] ( A g g r e g a t e , E v e n t ) = > A g g r e g a t e / / t h e r e f o r e w e h a v e ( A g g r e g a t e , C m d ) = > F u t u r e [ ( A g g r e g a t e , S e q [ E v e n t ] ) ]
  6. Async API - Inconvenience On creation ( c m d

    : C r e a t e F o o ) = > F u t u r e . s u c c e s s f u l ( F o o C r e a t e d ( " f o o " ) ) Post-creation ( f o o : F o o , c m d : C h a n g e N a m e ) = > F u t u r e . s u c c e s s f u l ( S e q ( F o o N a m e C h a n g e d ( " b a r " ) ) )
  7. Sync/Async API - Lift On creation C m d =

    > E v e n t C m d = > F u t u r e [ E v e n t ] / / Y e a h ! ! C m d = > T h r o w a b l e Post-creation ( A g g r e g a t e , C m d ) = > E v e n t ( A g g r e g a t e , C m d ) = > S e q [ E v e n t ] ( A g g r e g a t e , C m d ) = > F u t u r e [ E v e n t ] ( A g g r e g a t e , C m d ) = > F u t u r e [ S e q [ E v e n t ] ] / / Y e a h ! ! ( A g g r e g a t e , C m d ) = > T h r o w a b l e
  8. Akka And DDD/CQRS Is the Aggregate an Actor? Or does

    it live inside an Actor? If it lives inside an Actor, the Actor must know it’s hosting an Aggregate Akka Persistence for Event Sourcing Akka Persistence Query for generating Views (experimental)
  9. Protocol And Behavior Protocol is the set of commands and

    events for a given Aggregate Behavior is the implementation Conditions to accept commands Possible failures Modify Aggregate state
  10. Protocol And Behavior ┌ ─ ─ ─ ─ ─ ─

    ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ A g g r e g a t e │ │ P r o t o c o l │ │ │ ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ │ t y p e P r o t o c o l │ │ C o m m a n d s │ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ├ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┤ │ │ E v e n t s │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┴ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ B e h a v i o r [ A g g r e g a t e ] │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
  11. AggregateManager Create AggregateActors by id Forward messages to right AggregateActors

    ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ A g g r e g a t e M a n a g e r │ ─ ─ ─ ─ ─ ┐ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ A g g r e g a t e A c t o r ├ ─ ┐ └ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ ├ ─ ┐ └ ─ ┬ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
  12. AggregateActor AggregateActor is initialized with Behavior of Foo Responsible for

    Foo lifecycle and events storing ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ A g g r e g a t e A c t o r │ ─ ─ ─ ─ ─ ─ ─ ┐ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │ │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ B e h a v i o r [ F o o ] │ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘ Protocol messages are sent to Actor and applied to Aggregate through its Behavior
  13. Projections We read from the Event Store to produce Views

    Akka Persistence Query new experimental module Produces a Reactive Stream source with the selected events
  14. Shop Aggregates Customer just info from a customer Product create,

    change name and change price Order (references Customer and Products by identifier) created for a customer add / remove products execute / cancel
  15. Shop Projections Customer Aggregate event → CustomerView Product Aggregate event

    → ProductView Customer, Product and Order events → OrderView
  16. Problem With OrderViewProjection What to do with Events from Customer

    and Product? They will probably arrive before the first order is created. Should we query the CustomerViewRepo and ProductViewReop whenever we need more info? Will they reflect the expected state?
  17. Solutions 1. Have one single event stream and one consumer

    can be a serious bottleneck 2. Implement specific logic for each single event for each view can lead to increasing complexity 3. Copy data by reusing existing projections, but saving in another Repository need for more storage, but simpler and reusable code Demo project uses that approach (check it) 4. Synchronous views, at least the main views Response time penalty, but better user feedback