6
votes

Recently I've followed a CQRS workshop which made me wonder how events are stored when using event sourcing.

I think that after every single event the entire application should be in a valid state (otherwise the replay functionality is useless). This means that event should be stored in exactly the order they happened. I also believe that the order of events for all aggregates is important. For example, a user could make a product and an order (product and order both being separate aggregates, order references product through an ID). This means that the 'create product event' should be stored before the 'add product to event'. Otherwise replaying would could lead to an invalid state where the order, referencing the product, exists before the product exists.

How is this situation handled? Should you always send events to the database using a synchronous methods, for example by locking the database? Is this solution scalable? Or should you store events for each aggregate in a different table? But how do you ensure ordering then? Another option would be to store the time for each event, and sort by that. Is the precision of timers on a PC high enough to be able to do that?

2

2 Answers

6
votes

I know this is an old thread, but you're absolutely right to question this. The persistence of the events in an event store is irrelevant to your question. Timestamps are an invalid solution, and what the users can logically do is irrelevant to your question.

Your question, correct me if I'm wrong, is that once an event store publishes events via something scalable (for example message bus) - how do you guarantee that the denormalizers receive the events in the correct order. Message buses typically do not guarantee ordering of events.

The answer is you can't, so one option I would suggest is to provide version number with the event, and only update a projected model if the version number of the last known state matches that in the event. If it doesn't, configure the event to retry while you wait for the next event in line.

2
votes

You can take a look at NEventStore's source which does pretty much what you want. All events are stored in the order they are committed, the event store doesn't really care about your particular business objects, it just persists atomically a collection of events. It's up to your app to generate them in the right order.

Also, be aware that your business object should be a proper aggregate root and this means that, at most, it only has an id of another AR . One AR doesn't care about the other, but the business process will tell you in what order things should be done e.g: OrderCreated => order has been persisted => Create invoice (referencing the order) => Invoice Created.

For example, a user could make a product and an order (product and order both being separate aggregates, order references product through an ID).

No, it couldn't. It needs the product info before being able to create an order out of it. Customers don't add invisible products to their shopping cart. And customers don't create products either.

There's a lot to talk about this stuff, but in order for things to work properly you really need properly deigned domain objects and to understand what event sourcing (ES) really is (hint: it expresses object state as a stream of events).

Btw, when using ES, your focus should be on implementing it correctly at the object level, you shouldn't build your own event store.