I’d like to sparke some of my own thougts about your issue. Keep in mind that as you, I’m new to the concepts myself.
To start off i’d like to point out that events are really important, just as important as aggregates, the business logic etc. They drive everything so once the event is described it ideally should not be modified, it’s modification changes description of some part of the system.
As Wayne proposed, the migration between two versions of an event can be managed through introducing upcaster on the consumer side.
It basically ensures that this consumer is going to be able to handle new events.
For the time of your implementation of new event handler on consumer side, your consumer will not be able to process new type of an event.
Therefore when upstream service introduces new data in the event, this data will not be available for the downstream service, only after you implement new handler for the event you will be able to replay the events, upcast old ones and process new ones to project some data, do new business logic.
I’m not so sure as to why you are scared of them.
The bounded context that publishes the event does not care what the outside consumer is.
Instead of assuming that an event will be consumed by someone from the publisher perspective, I tend to think more on the customer side of things, “What i need this to fulfill my responsibilities”
The anti corruption layer.
It is a generic solution for things like that. When you introduce consumer of events, a microservice or anything really, it’s logic works with the events of your system until two things happen:
- Upstream drastically changes its logic and it’s event publication (behavior)
This scenario ideally should not happen, because it will also drastically change the implementation of the downstream service.
The work around on that is basically the same work as you did when you firstly introduced this downstream service, you assumed the logic of upstream and created logic accordingly, you need to re-do that.
- Upstream introduces new event (behavior)
When brand new event is introduced by upstream you basically can ignore it, if it does not affect responsibilities of downstream service, if it does, you need to implement appropriate behavior and possibly replay some parts from the event stream.
Upstream changes event (data)
This is basically it, isn’t it? When new event version is introduced, it means that some of the fields has been deleted, added, modified (name).
It should not really have anything to do with the intent of such event.
So the problem for downstream is that it does not recognize any of the data from this event, so once the upstream starts publishing such events the downstream logic will be halted at exactly the point where it handles the old event version.
This is where the upcaster comes in, it is not a simple mapper from v1->v2 though, here’s what i think about it.
When upcaster is introduced to downstream service, the downstream team must need to think for a while and decide what data should be put where there was no data before?
What are implications of this data? Can we do something cool with it? Most of the times, since the downstream was not designed to work with new data, it can be just blank, but you must consider the default if you want to do something with it properly.
Keep in mind that when upstream event changes its schema, both, the upstream and downsteam do not know what to do with previous events, and they should both decide what to do inside their own boundary.
What Wayne proposed is the solution i’d go with. You need to threat the events with special care, they are the source of Everything.
The dependencies should be thought of as ‘what i need’ instead of ‘who needs me’, the transparency in axon really helps here. The consumers are not dependencies, the Publisher of Consumer is the dependency on Consumer.
When you have let’s say 5 services that ought to work alone, separate teams, repos whatever. I think that ideally the downstreams should care about what’s going on with the upstream not the other way around, but you know different teams, different midsets, different needs. But that’s a human aspect of organization, when you code i do not think that you should care about what your downstream is doing.