Wrapping events in other events/commands - good or bad?

I’m quite new to ES, but have been doing DDD for a long time. I recently started working on a project that uses Axon and found a practice that, in my eyes, makes the system a lot more rigid and more difficult to reason about.

We have some commands and events wrapping other events.

  • Usually the Sagas wrap events into commands to dispatch to an aggregate. In this way, the piece of code that creates the event, has knowledge of what the events final aggregate expects. This feels like crossing an abstraction / responsibility boundary.
  • Some sagas start other sages, for these ‘child’ sagas to communicate back, they create events wrapping other events. These Russian doll events go first to the initial saga to do any required processing and then are used as in the scenario above (command nesting events).

Is this a standard, well understood practice with Axon/ES? Is it a recognised bad practice? or Is it something to (maybe) do in some very specific cases.

An unfortunate consequence of this, is that tests have more complex setup and assertions as there’s extra data flowing in and out of the sagas & aggregates.

Hi Augusto,

I’ll try to answer your questions. Sagas can be used for communication between 2 aggregates. The goal is to keep the knowledge of the Aggregate within the Aggregate. Let me give you an example if you book a flight, a seat in the airplane will only be reserved when you have paid and when the passenger is not on a no-fly list. The aggregates involved here are the Booking, Payment, and an aggregate that checks if the passenger is not on a no-fly list. In this case (Saga) event handlers can be used to store the state. An event handler method can be annotated with a StartSaga annotation which will tell the SagaManager to instantiate a new Saga instance. The Saga could start on a BookingMade event and then wait on both events (the BookingPaidEvent and the event that marks the fact that the passenger is not on a no-fly list). When both of these events are handled, the state of the Saga is updated and the Saga can send a command to the Booking aggregate to confirm the booking. This event handler can be marked with the EndSaga annotation and it will end the Saga. So an event starts a Saga and a Saga can not start another Sag directly. The event processors for the Saga work independently so the Russian doll should not be an issue.
Before using a Saga you should think about whether you need a Saga, if you don’t need state to base decisions on you can also use a (stateless) event handling component.
Testing Saga’s should not be complex if they are it could be an indication that something is wrong with the design. You can use SagaFixtures to create Given-When-Then style tests.
I hope this helps,

Best Yvonne

About the wrapping messages, it is not a good idea to wrap events in commands, messages should only contain the information that is needed for that command or event. The intent of a command or event should be clear

Hey @augusto
would it be possible for you to provide an example of “Sagas wrap events into commands” and “sagas start other sages”? Generally speaking, @Yvonne_Ceelie’s answer is a very good overview of the intended behaviour. But I have a feeling that you have some special and complex use case which I don’t quite understand. I hope an example would make things clearer.