Event Sourcing – How to Rewrite Events in EventStore

cqrsevent-sourcing

I'm thinking about whats the correct pattern to handle this case in CQRS / Event Sourcing:

I created events to calculate a balance and system goes into production.
By accident, this implementation has a bug and calculation of balance is wrong.

Should I fix the implementation and rewrite the events in the event store as well as the snapshots?
Do event store implementations provide this out of the box or do I have to solve this at the underlying DB level?

At a wider scope: what if event signature is changing (e.g. more fields added or fields renamed)?

I found these slides saying rewrite is the way to go:
https://ookami86.github.io/event-sourcing-in-practice/#slide-51

Best Answer

OK im going to add a quick answer, really need more detail on your particular case to explain i think.

You should never rewrite events in event stores.

Events in the store should be immutable and never change.

If an event occurs which is incorrect, then you must create a correction event which you apply to the object.

ie:

  1. account create
  2. withdrawal amend balance to -£100
  3. error correction correct balance to -£90

Reading between the lines of your question I think you are confusing the events held in the store, with the actions that occur in response to those events.

In this case we probably have a withdrawal event and a balance calc service which works out the balance. lets say the balance calc service has an error where it is not adding a the extra £10 charge to all withdrawals and you want to change the logic to fix this.

However, your problem is that you build the object state from the events in the store, so if applying that withdrawal event includes calling the service to work out the new balance then changing the implementation of that service will change the history of all your objects.

so your withdrawal event v1 comes in as

withdraw(amount = £90)

but is saved as

withdrawal
 amount = £90
 new balance = -£100

your withdrawal v2 coems in as

withdraw(amount = £90, applyCharges = false)

but is saved as

withdrawal
 amount = £90
 applyCharges = false
 new balance = -£90

when constructing the object from event store the new balance value is used rather than calling the service to calculate the new balance

Related Topic