Bug: Command doesn't map to the correct handler and arrives at an event hanlder

We’ve spent quite a few hours on this problem and haven’t yet dug into it’s root cause but have fairly sufficient evidence of the issue.

Defining the Problem:

SyncOnModelCreated (Event) arrives inside ExternalSyncServiceEventHandler which is then placed on the command bus AddSiteFromESS (Command)
This command should be picked up by a @CommandHandler inside the SiteAggregate for the above command. Instead it arrives on an @EventHandler for completely different event SiteRegister (Event). The event SiteRegister contains valid data and the original command AddSiteFromESS is never handled in this case.

Screen Shot 2019-05-19 at 7.39.35 PM.png

Reviewing the tracestack we can see that right up to the loading of the Aggregate AddSiteFromESS is in the variables window as the command we should handle.

Screen Shot 2019-05-19 at 7.40.53 PM.png

By the time we get to executeWithResult it is now trying to iterate over an event for SiteRegistered (which should not have been triggered in any way).

Screen Shot 2019-05-19 at 7.47.37 PM.png

The top of the tracestack has us inside the SiteAggregate for the handler of the SiteRegistered event which is where the breakpoint is set.

I would be happy to share more information from the tracestack as well as the variables but at the moment we are dumb founded. We’ve been able to reproduce this on multiple machines, with as much isolation of the problem as we could.

Attaching above screenshots since they are very small in the original post.

Screen Shot 2019-05-19 at 7.32.41 PM.png

Screen Shot 2019-05-19 at 7.47.37 PM.png

Screen Shot 2019-05-19 at 7.40.53 PM.png

Screen Shot 2019-05-19 at 7.39.35 PM.png

Hi Michael,

looking at the stacktraces and variable views, I don’t see anything out of the ordinary. The event being handled is due to event sourcing. As you can see from the “Streams” -> “0” variable value, this is a DomainEventStream, indicating that these are messages received from the event store to instantiate the aggregate.

The stacktrace also shows that you are still in the “Repostory.load()” method (AbstractRepository.load, line 115) . Command execution will only happen after this load method completes. If the command handler isn’t invoked, you should check the behavior of the aggregate after loading has been completed.

Cheers,

Allard,
Your response hinted at something rather obvious in hindsight but it was a result to a clear misunderstanding of how Axon works.
We had included an @EventHandler with @AllowReplay(false). We had incorrectly assumed that when placed inside an Aggregate these handlers would not be replayed when the Aggregate was loaded. This is not the case.

We’ve set up new rules for our team to follow:

  • Inside of aggregates only include @EventSourcingHandler and @CommandHandler
  • Do not apply(…) any events inside @EventSourcingHandler
  • Create a separate EventHandler outside of the Aggregate which handles all other events, loads the Aggregate from the Repository and applies appropriate events or performs said logic.

Do you agree with these constraints? I’m struggling to think of a situation where calling an apply() inside @EventSourcingHandler or @EventHandler (that is inside an aggregate) would not result in side effects.

Hi Michael,

I’d like to share my thoughts on the three ‘rules’ you’ve defined for your team:

Inside of aggregates only include @EventSourcingHandler and @CommandHandler
I definitely agree, that an Aggregate should only contain message handling functions annotated with @CommandHandler and @EventSourcingHandler.
Thus, this is a fine rule to state in your team I’d say!

Do not apply(…) any events inside @EventSourcingHandler
I think this is also a good rule of thumb to maintain.
However, note that the AggregateLifecycle#apply(Object…) method will always check whether it’s in a life state prior to actually publishing the event.
Thus, if your Aggregate is being event sourced, the apply({your-event-object}) call should do nothing.
If you are uncertain whether this is the case, you could wrap the apply() call in an if-block where you utilize the AggregateLifecycle#isLive() to check whether the Aggregate is being event sourced, yes no.

Create a separate EventHandler outside of the Aggregate which handles all other events, loads the Aggregate from the Repository and applies appropriate events or performs said logic.
I am not entirely certain where this rule comes from to be honest. Or maybe I just don’t understand the set up of it.
Regardless, I’d like to state that if you want to perform an operation on an Aggregate, that should ideally be modeled as a command.
Commands are expressing the intent to perform some operation, thus to perform some logic.
The events which typically flow out of this decision making step should just be regarded as notifiers to the world that something has happened, thus the confirmation of the expression of intent (the command).

Lastly, from what you’ve shared with us here, I get the idea that you’re loading the Aggregate manually from the Repository.
Note, that the framework can do this for you if you have a command handler on the Aggregate.
However, if you would like to maintain the manually loading approach, it’s suggested to use the Aggregate#execute(Consumer) or Aggregate#invoke(Function<T, R>) methods on the retrieved Aggregate from the Repository.

Concluding, I hope this helps you out Micheal!

Cheers,
Steven