Linking the state of two Aggregate instances using a Saga

Hello there!

I am trying to embed Axon Framework 3.4 into an existing project and use it to reinforce the modularity of this microservices-based application.
Among many use cases to cover, I would like to consult with the community one involving “linking” the state of two instances of an Aggregate.
A heads up disclaimer: the project is commercial and the client is considerably strict about their business logic, so “redesigning how it works” is not a valid solution, albeit may be tempting.

The idea is: System manages a collection of Aggregates which are editable by the User. At any point, the User may decide to ‘link’ selected Aggregates, i.e. couple any further edits so that they are batch-applied to any of the linked instances of the Aggregate. If the name of the InstanceA changes, so has to the name of InstanceB.

Given that a link can also be removed at will and the instances of the Aggregate may be a source of truth for some other bits of the system, merging the objects upon link and reconstructing them at un-link seems unnecessarily complicated.
Reading the Axon Reference Guide I have quickly come to the idea of using Saga(s) to handle this scenario - I have the perfect candidates for Saga-creating and Saga-closing events after all. I do struggle with wrapping my head around two nuances though:

  1. How will these Sagas handle multiple links being sustained in the system at once? If I understand correctly, one saga should be created for each instance of the link, each attending to one linked group of Aggregates? Per the docs, "By default, a new Saga is only started if no suitable existing Saga (of the same type) can be found." Based on what will Axon try to establish if a new copy is needed? Similarly - based on what data will the un-linking event of two Aggregates be handled by the appropriate copy of the Saga?

  2. Ideally, to limit the boilerplate, I would like to use the same Command / Event set for the edition of linked and non-linked Aggregates. After all, the fundamental idea of the functionality is to allow the User applying their changes to a single instance of the Aggregate and have the distribution of these changes to other appropriate instances handled automatically by the System. How should I approach it through that so - having instances no. 01, 02, and 03 of the Aggregate, 02 and 03 being linked - an edit command for Aggregate 01 will be handled by the Aggregate 01 itself, but the similar command for Aggregate 02 or 03 is first intercepted by the Saga and then re-distributed to both?
    I am looking forward to hearing from more experienced users of the Axon Framework. Perhaps my idea for use of the Sagas is wrong in the first place to begin with? If so, how would you handle the scenario in your code? Preferably keeping the idea of the ‘link’ out of the aggregate, for transparency? Should I move the Aggregate Root one step up and have a Saga / Handler juggle the instances of the current Aggregate between this new Root?


Hi Szymon,

as with many design questions, it’s very important to take a step back and look from a slightly higher abstraction level to the challenge. First, at least a level where the aggregate boundaries aren’t visible :wink:

Basically, you have 2 “editable things” and users can link 2 editable things. This would indicate that you have something like “EditableThingCreatedEvent” and “EditableThingsLinkedEvent”. This is basically all the events you need to create your view models, right? So from here, a user can find out whether the things are linked or not.

Next, we need to check if there are invariants. The challenge seems to be that the Things aren’t editable once they’re linked. First question you should ask yourself: it this an absolute consistent requirement? If not, just have the editing commands verify if any links exist. In that case, the event doesn’t even need to be handled by the aggregate. Just have a 3rd component manage the links between these Things.

If strong consistency is required, you’ll need some sort of process. First, a command that requests the creation of a link. Then, the component that handles that command will register the link on the first aggregate, and then on the second. If one of them fails, the link registration is removed from the first aggregate. Lastly, the command is confirmed. The Aggregates themselves have reported links (in both directions), allowing the view models to respond to those as well.

Hope this helps.