Does events triggered by command handlers gets consumed first by aggregate and only then by event handlers

Hello Team,

Apologize for naive question.

When events get triggered by command handler via Aggregate.apply(), does these events first gets consumed by the aggregate event sourced handler and only after the execution completion of the event method handler, is then consumed by the other event handlers. Do we have any such hard order defined ?


Kartik

No worries, Kartik, all questions are fair if you ask me.
The answer is pretty short, too, so let me break it down for you.

The AggregateLifecycle#apply method will firstly invoke all @EventSourcingHandler annotated methods within the scope of the aggregate with the new event. The event will be published on the event bus only after the command handling method is finished.

Publication on the event bus will, in turn, result in other event handlers being invoked.

Sorry @Steven_van_Beelen for not being clear. Let me put it in this way.

  1. command triggers event using AggregateLifecycle.apply()
  2. @EventSourcingHandler is invoked inside aggregate for that event
  3. completion of the above event sourcing handler method execution
  4. event is recorded in event store server
  5. event is published to other @EventHandlers

If the above flow is correct, does this apply to all the commandbus implementations too ?


Kartik

No worries Kartik, let met break it down for you in code:

class SampleAggregate {
    @CommandHandler
    public void handle(SampleCommand command) {
        // 1. validate state
        // 2. publish event
        AggregateLifecycle.apply(new SampleEvent());
        // 4. proceed with rest of method
    }

    @EventSourcingHandler
    public void on(SampleEvent event) {
        // 3. update state
    }
}

So, instead of steps 4 and 5 in your sample, you would first reenter the command handling method if there’s more to execute there.
Only once the entire command handler has finished will Axon’s UnitOfWork commit the event publication transaction (as you described under step 4).

Step 5 is asynchronous from the command handling process, as this is a different thread given the nature of the Streaming Event Processors.

Thank you @Steven_van_Beelen for the clear explanation.