Conflict resolution

Last updated last month

One of the major advantages of being explicit about the meaning of changes, is that you can detect conflicting changes with more precision. Typically, these conflicting changes occur when two users are acting on the same data (nearly) simultaneously. Imagine two users, both looking at a specific version of the data. They both decide to make a change to that data. They will both send a command like "on version X of this aggregate, do that", where X is the expected version of the aggregate. One of them will have the changes actually applied to the expected version. The other user won't.

Instead of simply rejecting all incoming commands when aggregates have been modified by another process, you could check whether the user's intent conflicts with any unseen changes.

To detect conflict, pass a parameter of type ConflictResolver to the @CommandHandler method of your aggregate. This interface provides detectConflicts methods that allow you to define the types of events that are considered a conflict when executing that specific type of command.


Note that the ConflictResolver will only contain any potentially conflicting events if the Aggregate was loaded with an expected version. Use @TargetAggregateVersion on a field of a command to indicate the expected version of the Aggregate.

If events matching the predicate are found, an exception is thrown (the optional second parameter of detectConflicts allows you to define the exception to throw). If none are found, processing continues as normal.

If no invocations to detectConflicts are made, and there are potentially conflicting events, the @CommandHandler will fail. This may be the case when an expected version is provided, but no ConflictResolver is available in the parameters of the @CommandHandler method.