Architecture – Event Sourcing, Sagas, Bus, and Eventual Consistency

architectural-patternsArchitecturecqrsevent-sourcingeventual-consistency

I am currently learning about Event Sourcing via the book Microsoft .NET – Architecting Applications for the Enterprise. Event sourcing is, in my own words, an architectural pattern of storing "events" instead of "current entities". Current entities can be created by looping over the events belonging to it.

The problem of performance of creation of current entities can be mitigated by creating an extra storage where periodically the current entities are "snapshotted" (created from the previous snapshot and the events that happened after it).

In the book the architecture belonging to Event Source is setup as follows:

Event Sourcing in the book

Here all events (related to a Waterpolo match) are stored in a NoSQL RavenDB store. We also see a bus to keep track of events and a saga which belong to groups of events.

I have a few questions about Event Sourcing (I decided to ask them all at once since all questions relate to the description in the book):

  • I am wondering in what way these events would be stored. I can imagine that the data in events can change over time (extra properties, new event names) and that events need to be easily related to each other and itself. How does the actual structure of the database and data access code look to facilitate change and data retrieval?
  • What is a saga? Why is it called a saga? Are they persisted and if so, how?
  • How does a bus work? What are the advantages over just writing events directly to an event store?
  • In the above architecture where commands and queries are separated (CQRS) and the commands are implemented using Event Sourcing while queries read from the snapshot, what happens when data needs to be displayed during the initiation of a command? (E.g., showing bank account data while a user wants to make a deposit, based on this data.) How, in practice, do we make sure the data displayed is up to date?

Best Answer

Event storage

Event storage will depend on your application but it is a lot easier if you use a flexible storage for your events (so a NoSQL DB, JSON or XML). How you deal with updates will depend on several factors you need to take into account such as requirements for availability and timeframes for updates, amount of events, etc...

  • Update your events when your application updates: as part of the deployment of a new application, update all your previous events to the new schema
  • Version your events: have a version-id on your event. When an event is read from the database some piece of code knows how to 'upgrade' older events to the current structure. Like the first option, but basically 'on demand'
  • Throw away your old events: when your application updates, make a snapshot of all entities and throw away (or archive) the old events.
  • Never throw away old events: basically keep 'PurchaseOrder' forever. When you need another field, use a new event such as 'PurchaseOrderWithCouponCode'.

Saga's

A saga is basically a long-running event chopped up into pieces. This might be due to different reasons: it could be because you want to have an action that results in multiple events handled in parallel to avoid blocking with a transaction, because you need to coordinate several external systems, or because you need to coordinate with events that cross a bounded context. You need to persist them because of that reason: a saga can be started, launch a few events and at some non-deterministic point can have to resume by launching more events. Udi Dahan has a good introduction on this.

Message buses

There is a lot that can be said about buses. They abstract a large part of the storage of events for you and can handle more complicated scenario's, for example when you have multiple applications that need to work with the event store. For small applications you can write directly into the event store (and the code that would do that could be considered a bus...)

Data up to date

Short answer: you don't. Event sourcing works around this in several ways because you are 'eventually consistent'. In this example, you could simply display a message to the users that it might take up to ten minutes for deposits to show up...

Related Topic