Saga sends Command back to its Aggregate

Hello

I just switched from the SimpleCommandBus to AsyncCommandBus. Because of this switch I had to change the publishing method of commands in one of my sagas from sendAndWait to send. Using send caused a Deadlock when loading the state of an aggregate.

So whats my situation
I have an aggregate A which uses a Saga S to handle it’s long-running tasks. I make an example to make this clear. The logic in aggregate A decides that a long-running task T as to be executed. Aggregate A therefore fires an event E which is handled by Saga S. Saga S then calls one ore more services to execute this task T. I think using a saga is the right choice here.

So when the task is finished the Saga S sends a command which is handled by the same Aggregate A. Aggregate A then may decides to execute a further task which again would be handled by the Saga S or to send a “finish-event” which causes the Saga S to end.

Now to my question
In the intro I told that I had to change the way the Saga S sends commands (from sendAndWait to send). Because of that I made some research and found a comment in this google group that it would be a code smell when saga sends commands back to its calling aggregate (see post)!

Now I am wondering how I should model my logic? Any hints are highly appreciated :slight_smile:

Cheers
Marco

P.S: I am using axon-framework 3.3

Hi Marco,

if your Saga is doing long-running tasks, then you should definitely consider running it asynchronously. Your problem is not so much the CommandBus being async, but the Event publication (or handling) still being synchronous. You can configure your Saga to run asynchronously by configuring it in a Tracking Processor. Once you do that, it doesn’t matter anymore if you use send or sendAndWait.

That said, Axon 4 has some significant improvements over Axon 3 when it comes to asynchronous handling. For one, the nuber of threads used by a Tracking Processor can be changed dynamically. Have you considered upgrading?

Cheers,

Hi Allard

Thanks for your help.

So you suggested to use tracking event processors for sagas only. Could you tell me how I enable this only for a certain saga? Doing that I could switch back to the SimpleCommandBus which would actually be great.

I understood correctly that when using the SimpleCommandBus the “send” Method is logically the same as “sendAndWait” as it is synchronous in any case?

In my question I mentioned the situation where a saga is sending back commands to the aggregate which triggered the event. According to your post (link) this is a code smell. Can you tell me how this should be handled ord can be improved?

Cheers
Marco

Hi Marco,

Sagas are a special type of event processors. Saying that you can configure this Saga only to use Tracking processor:

In the Spring Boot app:

  • add this to application.properties: axon.eventhandling.processors.MySagaProcessor.mode=tracking
  • add an annotation to your Saga class: @ProcessingGroup(“MySagaProcessor”)

For plain Java configuration please refer to the official documentation: https://docs.axoniq.io/reference-guide/configuring-infrastructure-components/event-processing/event-processors#configuring-processors
The EventProcessingConfigurer class defines a number of methods that can be used to define how processors need to be configured.

EventProcessingConfigurer.registerTrackingEventProcessor(String name) defines that a processor with a given name should be configured as a Tracking Event Processor, using default settings. It is configured with a TransactionManager and a TokenStore, both taken from the main configuration by default. Please note that we named this processor explicitly with @ProcessingGroup(“MySagaProcessor”). If you do not specify the processing group name (@ProcessingGroup(“MySagaProcessor”)) of your processor, it will be the full package name of your Saga class.

“a saga is sending back commands to the aggregate which triggered the event” -> Saga is usually used to connect two aggregates in the BASE transaction. Having Saga with a method that receives the event and publish command to the same aggregate (in this same method in Saga) is probably not needed. This usually means that you are leaking some decision-making code from Aggregate to Saga.

Best,
Ivan

Hi Ivan,

I don’t get you answers really together with my problem with saga replay configuration described also here:

https://groups.google.com/forum/?utm_medium=email&utm_source=footer#!msg/axonframework/7fff4_6EUQQ/SMv_qYQTAgAJ

Setting mode tracking works fine but it seems this config is only available through auto config. If I use TrackingEventProcessorConfiguration in the link above this option is not even available. Also setting the processing group is not needed to remove the whole package name! We got the name of the saga already without doing anything. Can you maybe check what can be wrong with my saga config in the link above? There also the error message is provided.

One more hint. As soon as you use java configuration you need to remove every setting from the application.yaml because otherwise you get “processor” already found exceptions!

Best, Michael

Hi Ivan,

some feedback here?

Best, Michael

Hi Ivan,

You mentioned:

“a saga is sending back commands to the aggregate which triggered the event” -> Saga is usually used to connect two aggregates in the BASE transaction. Having Saga with a method that receives the event and publish command to the same aggregate (in this same method in Saga) is probably not needed. This usually means that you are leaking some decision-making code from Aggregate to Saga.

For the scenario where we are required to interact with an external API to process a command does it make sense to use a saga to encapsulate this logic?
The saga would then issue a command back into the aggregate that started it.

Or would it make more sense to use an event listener @Service that sits in the same package as the aggregate?

Hi,

I see you want to interact with external API, and you have to coordinate these actions.

Sagas are event processors as well, the difference is that they are stored in a DB (which can influence on performances) to preserve some intermediate state, but usually you do need to store this state, as your messages (events, commands) are caring this reference information already. So, the regular event handler can be utilized to implement Saga pattern as well

I would suggest encapsulating the logic of translating API messages (request,response) to (commands,events) in an independent components/services you can call adapters for example, to protect your ubiquitous language better.

Best,
Ivan

So yes, you can use Saga pattern for this. Stateful (with Saga annotation) or stateless (just regular event handler processor) depending on the need.
What I would suggest is for this Saga to send Commands and handle Events. It should not be aware of the external API. These commands and events are part of your bounded context. The adapter, I have mentioned before, would be responsible for translating this command to external API (request) and external API response back to the event. Think of it as an anti-corruption layer. Such an adapter component would be external command handlers able to handle command from your aggregate/saga and translate it to request, and it could translate response back to the event (with publishing it to event bus).

Best,
Ivan

There are many different topics on this thread that are not related to the title :slight_smile:

To answer this:
“a saga is sending back commands to the aggregate which triggered the event” -> Saga is usually used to connect two aggregates in the BASE transaction. Having Saga with a method that receives the event and publish command to the same aggregate (in this same method in Saga) is probably not needed. This usually means that you are leaking some decision-making code from Aggregate to Saga.

The important part of this message is (in this same method in Saga). Saga is constructed of several methods that can receive an Event and in return send Command. They are designed to connect concepts. If ONE method of the saga would be receiving the event from Aggregate1 and send a command back to the same Aggregate1 that would be a design/code smell. Usually, you want to send this command to Aggregate2 (another concept). If you send this command back to Aggregate1 that really means that you are leaking some logic from the Aggregate to this Saga which you should not do. Aggregates should do the work!

Threat your third API service as a foreign concept (imagine that it is another aggregate somewhere there in the wild). You additionally need to map the APIs in the adapter components (ACL).

Best,
Ivan

Best,
Ivan

Hi Ivan

The point is that the saga is executing blocking calls which may take a while until being finished. As far as I understood service calls should be done in sagas and not aggregates. Moreover I don’t want to lock my aggregate for the duration of the service call.

What’s your opinion?

Cheers
Marco

Hi Marco,

in that case, your Saga is coordinating between an Aggregate and a 3rd party system. That’s fine. It’s only a design smell when there is only the aggregate and a saga involved. In such a case, you should check if the logic the Saga is performing couldn’t be moved to the aggregate itself.

Cheers,