As our axon models evolve, we add new events and make additions to existing events. We run into issues when something happens after a release and we are forced to backout the changes. New or changed events may have made their way into the database, so once the changes are backed out, we will get serialization issues for those events when they are re-played. We are wondering if there is some strategy to manage these cases. It’s a live system, so we can’t backup and restore the database if the release needs to be backed out.
some companies I have visited have a “roll-forward only” policy. They never roll back a deployement. Instead, they fix and redeploy. Unfortunately, that’s not (yet) an option for everybody.
In general, my recommendation is to make sure your changes are backward and forward compatible. It’s easier said than done, and probably also easier done that you might think. Main thing is to only add new fields, not change/remove any. Your serializer will also have to be lenient. It shouldn’t fail if it receives a property it doesn’t know. Preferably, it should also not fail when an expected property is missing.
Axon’s serializers aren’t lenient by default, but it’s easy to configure them to be:
Hope this helps.
Thanks Allard, that will definitely help with a lot of the changes we make. Is there a way to configure it to ignore entire events it doesn’t understand for the cases where we add a new event and need to rollback?
for Event Processors, unknown event types are automatically ignored. However, in the case of Aggregates being event sourced, we have decided to fail by default, instead. The thought behind this, is that when streaming an Aggregate, you should not encounter unknown events, as the aggregate itself is the one who published them. Event Processors, on the other hand, may live in external applications, and they should only need to hold the classes they care about receiving.
It is the EventStorageEngine implementation that explicitly defines certain streams should raise an error when an unknown event type is encountered. You could change this behavior by overriding the org.axonframework.eventsourcing.eventstore.AbstractEventStorageEngine#readEvents(java.lang.String, long) method. Instead of passing “false” as the fourth parameter to EventUtils.upcastAndDeserializeDomainEvents, you simply pass true (i.e. ignore unknown events).
Alternatively, you could wrap/override the behavior on the Serializer, telling it to return a dummy event implementation when an unknown class is encountered.
I am going to give this a bit more thought to see if there is a neater way to resolve this. If you have any ideas, they’re most welcome.