Purpose of associationProperty property within @SagaEventHandler

Hi,

I have hard time understanding the meaning of associationProperty within the SagaEventHandler annotation.
I’ve read a from few different sites (including the Axon official docs) but I can’t understand its roll and how it related to aggregate

Thank u in advance

Hi Eyal,

Since a specific saga could be triggered potentially by any event from any aggregate, we need a way to easily get the saga instances that have a handler for an event. The association property is used for this. Underneath saga’s are processed by an event handler.

Most of the time a specific saga needs to react on one ore a couple of specific aggregates. For example if I use a saga to transfer money from one account to another, only the events for those two accounts are applicable to the saga.

Maybe the javadocs also help to get it more clear.

I hope this helps, don’t hesitate to ask follow up questions.

1 Like

I had a similar problem when I first learned about sagas. The confusion seems to be because the docs don’t mention the keyName and just explain the default behavior.

If you look at the @SagaEventHandler javadoc, you will notice there is an optional keyName. So let me explain with an example. Say you have this:

@StartSaga
@SagaEventHandler(associationProperty = "orderId", keyName="orderKey")
public void handleNewOrder(OrderCreatedEvent orderCreatedEvent) {
 ...
}

When an OrderCreatedEvent is processed a new saga instance is created (due to @StartSaga). That instance is associated with a concept that consists of a key and value. The key, in this case, is orderKey. The value is taken from the orderId property of the orderCreatedEvent. For example, if orderCreatedEvent.orderId is 5, this sage instance is associated with the orderKey=5 concept.

In the same saga, you may also have

@SagaEventHandler(associationProperty = "orderId", keyName="orderKey")
public void handleShipment(ShippingEvent shippingEvent) {
...
}

The same rule applies here (orderKey = shippingEvent.orderId). That means that the saga instance will not react to every ShippingEvent message in the system but only to those matching the associated concept. Following the example above, that is only the events for which shippingEvent.orderId = 5. In other words, a ShippingEvent message where the orderId is not 5 will not make that saga instance execute the handleShipment method.

When you want the keyName to use the same name as the property of the event from which it gets the value (which is often the case), you may skip the keyName. So the following 2 lines are semantically identical

@SagaEventHandler(associationProperty = "orderId", keyName="orderId")
@SagaEventHandler(associationProperty = "orderId")

Please note that setting the association via annotation only works in @StartSaga methods. In all other handlers, it is used for checking the association ( :thinking: perhaps we should have distinct annotations). If you want to set more associations or you need to do it at later stage, you should use the API. For example:

SagaLifecycle.associateWith("orderId", shippingEvent.orderId);

I hope this helps understand the concept.

1 Like

Thank you for your answers.So there is no connection between the Saga and aggregate via this properties right? The property is only like a primary key in RDBMS right? (I’m coming from RDBMS/JPA/Hibernate worlds so I’m seeking analogies to understand it better)

Can I use Saga to listen to all events?
Say for example I have Car manufacture and every time a new car is ready I want my Saga to listen to newCarCreatedEvent and do some stuff…So I want my saga to be open for app lifetime

No, a Saga can’t listen to all events. A Saga is used as communication between different aggregates mostly.

If you want to do x for every instance of event y, a regular event processor will do.

1 Like

There is no direct connection between a saga instance and an aggregate instance. A saga instance often coordinates multiple aggregate instances, so it needs to be able to react to events concerning any of them.

If you want to conceptually map it to the RDBMS world, think of it like a table with all saga instances. When you create a saga row (instance), you provide a value for the mapping_key and mapping_value columns. When an event is processed, the system will try to find the right saga instance by doing something like

SELECT *
FROM saga_instances
WHERE event_type = ?
AND mapping_key = ?
AND mapping_value = ?

Of course, this is an oversimplified pseudo-code just to help you make the analogy. In reality, it’s more complex than that, but I hope you get the idea.

I think I’m starting to get it :slight_smile: -
thank you .
Is it code smell to use query command inside saga?
Say for example I need to decide if to send command based of some data associated with particular aggeration.
For example - saga handles event of type X and based of state of property of aggregate D we send command for aggregate B

I moved that question to a dedicated topic and will answer there: Is it code smell to use query command inside saga?

1 Like