What is the reason / purpose for Saga association?

Hi Folks,

I’m trying to understand the essence of the saga association.

If I got it right, the associationProperty is used for the routing of an Event to specific Saga instance. Having an events

class Foo {
private MyType myId;

}

class Bar {
private MyType myId;

}

and writing a Saga:

class MySaga {

@StartSaga
@SagaEventHandler(accotiationProperty = “myId”)
public void on(Foo e) {
// do something here
}

@SagaEventHandler(accotiationProperty = “myId”)

public void on(Bar e) {
// do something here
}

}

would start a new Saga instance on receipt of Foo and assign the value of “myId” from the event to a (internal Saga) property myId (I could have renamed it by using the keyName, but this is just a detail).
Now if I had a second event Bar, using the the same assotication property myId (same type, same value) and an event handler in the Saga, the SAME Saga Instance will be called on the arrival of the Bar event.
This is simple routing, straight forward, but I want to have written it down.

Now I was reading the Chapter https://docs.axonframework.org/part2/sagas.html#managing-associations of Saga documentation and didn’t get the point there. You are writing that the Saga gets associated with “instances of those concepts”.

Do you mean Aggregate?
The association is somehow fuzzy - the aggregate publishes some Event with some property (not neccessarily an Aggregate Identifier) - it creates a “logical” connection between the aggregate and the saga.

It get even more unclear to me, if you describe the SagaLifecycle methods.

What are they for?
What is the purpose / intent / reason for assotication the Saga with Aggregates before sending commands to them?
Should the association executed with SagaLifecycle MEthods points to TargetAggregateIdentifiers inside of the commands?
Another question is, why do I have to use a String or a Number (and not ANY (nice = Java Bean, Serializable) type, like in AggregateIdentifier)?

Somehow it is just not stated in the docs why should I want to do so. I perfectly understand your business example - it makes absolutely sence, but the technical code snippet leaves some white spots…

Thanks

Kind regards,

Simon

Hi Simon,

Saga Associations are, as you said, the mechanism to invoke the right Saga instances for an incoming event.
Basically, an association contains a key and value. The key is what you specify in the Saga class, the value is retrieved from the actual event.
When a Saga starts, it is automatically associated with the property (and value of that property in the event).
However, Sagas often need to coordinate between several aggregates, components or whatever. As a Saga only observes events, the separation into aggregates is completely irrelevant from their point of view. That’s where the SagaLifecycle comes in. It allows you to associate that instance with other ‘concepts’.
Imagine a saga coordinating shipments for an order. When it receives an order, it creates one or more shipments (maybe subject to product availability, or desired delivery dates, etc). Before sending ‘createShipmentCommand’s, the Saga would associate itself with ‘shipmentId’->’whatever id is sent with create command’. This way, the Sag instance is able to receive events from that shipment.
Whether shipment is an aggregate on its own or not is, again, completely irrelevant. The Saga just wants to know about things that happen to specific shipments. So as long as the Event contains a reference to the shipmentId, the Saga will receive it.

The reason only primitives, Numbers and Strings are supported, is because these identifiers are used to locate Sagas. Databases aren’t good at looking up data based on blobs of serialized data.

Hope this clarifies things. We’ll look into the documentation to see if we can update it.

Cheers,

Allard

Thank you - it now becomes clear.

So the association id registered with Lifecycle methods before the command is send, is the id, that is read from the event received in another Saga method. From Saga point of view it doesn’t matter how this happens, but usually there is an aggreggate receiving this command (for the given target aggregate identifier) and emits an event putting this identifier back… (I know there might be exceptions, but this is the primary purpose).

Having Number/String as the is seems to be a little fishy, since current API allows the TargetAggregateIdentifier/AggregateIdentifier to be a custom type. Generally, I would expect the association value and AggregateIdentifier to met the same requirements, since usually the associtiation property IS the aggregate identifier.

By the way, I started to write down the statements we discussed here: https://zambrovski.gitbooks.io/software-architecture/content/cqrs.html

Hi Simon,

to avoid misunderstanding: note that the association values aren’t registered automatically when sending a command. You must do so yourself before sending it. Axon doesn’t know if you’re interested in listening to the events originating from that command…

Cheers,

Allard

Hi Simon, Allard,

I do think an addition to the SagaLifecycle to introduce a ‘associateWith(String associationKey, Object associationValue)’ might be in place, as internally the association values as does the TargetAggregateIdentifier set up) calls the ‘toString()’ function of the value any how. So that should work just fine for any Object you pass it to.

Nice bit of documentation there btw :slight_smile:

Just curious though, but what for are you documenting that, for your self, your team, friends/family?

Cheers,

Steven

Currently it is for me and some guys I’m are playing with AxonFramework with…

Maybe at some point the documentation will go to AxonFramework / AxonIQ in terms of beginners guide or something. Who knows? :slight_smile: