gautema / CQRSlite

A lightweight framework to help creating CQRS and Eventsourcing applications in C#
Other
1.1k stars 266 forks source link

Maintaining tracked aggregates in Session.Commit in case of exception #85

Closed krawuzikapuzi closed 5 years ago

krawuzikapuzi commented 5 years ago

In Session.Commit, the actual save to the repository (e.g. a SQL event store) or an event handler called within _repository.Save might cause an exception which will be passed on all the way to the initial call. However, the _trackedAggregates dictionary in memory never gets cleared, therefore the _trackedAggregates and the actual state within the event store diverge.

In our case we used a SQL event store that also publishes the events. During handling of the event an exception occured so the events never got committed to the event store. The events have however in memory been flushed using AggregateRoot.FlushUncommittedChanges, so version numbers have been increased already in memory, however the _trackedAggregates never got cleared. As long as the application was running, this hasn't been noticed, since Session.Get always returned the aggregate from the _trackedAggregates since IsTracked() returns true with the correct version number. Handling the next event for the same aggregate worked just fine, so the version got increased again and committed to the SQL event store. We ended up having version gaps in the event store but no in memory. After application restart obviously an out of sequence exception occured since the aggregate wasn't tracked yet but instead loaded from the database,

With this pull request we make sure that _trackedAggregates is maintained correctly, not causing any version gaps in case of exceptions in the event store or event handlers.

gautema commented 5 years ago

Thank you for your pull request. It has been merged now, and I'll create a new release.