I am currently working on a project where I’m using:
Axon Framework version 4.5.15
Spring Boot 2.3.10.RELEASE
Java 8
My application is using PostgreSQL as the underlying database. I have defined an aggregate with commands and event sourcing handlers. Some of the event sourcing handlers also publish additional events.
However, I’m encountering a ConcurrencyException when handling a command, specifically:
Command resulted in org.axonframework.modelling.command.ConcurrencyException: An event for aggregate [<aggregate_id>] at sequence <id> was already inserted.
Here’s an example code snippet of my aggregate definition for reference:
@Aggregate
public class MyAggregate {
@AggregateIdentifier
private String aggregateId;
@CommandHandler
public void handle(SomeCommand command) {
AggregateLifecycle.apply(new SomeEvent());
}
@EventSourcingHandler
public void on(SomeEvent event) {
// Perform some logic
AggregateLifecycle.apply(new AdditionalEvent());
}
}
I would like to understand why this exception is happening and how I can prevent it from occurring. Are there any common causes or pitfalls that can lead to this exception in Axon Framework?
These kinds of exceptions can’t be prevented entirely since we value consistency. When multiple applications handle commands for the same aggregate, the exception can be triggered. One of the ways to make these exceptions much less likely is to route the messages smartly by sending all the commands for the same aggregate to the same instance. Axon Server can route the messages for you to reach this. What do you currently use to route your commands?
I didn’t properly read your code sample before replying. Sorry for that. You should not use the apply method in an EventSourcingHandler as that would create a loop. You likely want to set the aggregateId from the AdditionalEvent, and nothing more.
I’m currently using SimpleCommandBus to route my commands. I’m routing all the commands for the same aggreagte to the same instance already. Do you think that publishing additional events in event sourcing handlers is causing the issue?
After reacting, I saw I didn’t look at the code well enough. The only thing the EventSourcingHandler should do is update the aggregate’s state. The SimpleCommandbus is not a problem for now.
Applying my advice to your example, you would need something like:
@Aggregate
public class MyAggregate {
@AggregateIdentifier
private String aggregateId;
private int someValue;
@CommandHandler
public void handle(SomeCommand command) {
// Optional checks if the command is valid with the current state of the aggregate
AggregateLifecycle.apply(new SomeEvent());
}
@EventSourcingHandler
public void on(SomeEvent event) {
// Update aggregate state
someValue = someValue + event.something;
}
}
You are facing this issue because two or more different threads/application instances are handling commands for the same aggregate instance.
When this happens, Axon Framework will happily load the instance on both (or more) processes.
But, event publication enforces that the “aggregate identifier to sequence number” combination is unique.
As Axon Framework bases the sequence number on the previous set of events, which is identical on both processes, both will try to insert an event at the same spot.
The uniqueness requirement kicks in, throwing an exception, leading to the ConcurrencyException you are facing.
The solution to this, as @Gerard already pointed out, is to use a distributed version of the CommandBus.
The SimpleCommandBusis not a distributed version.
As such, we would recommend you to use Axon Server or configure a DistributedCommandBus, using either the JGroups or SpringCloud extension provided by the Axon Framework team.