Conflict resolver

Hello guys,

I’m struggling with the conflict resolver mechanism even with the documentation and some examples.

I implement my own ConflictResolver class (let’s call it MyConflictResolver).
Meanwhile, I created a command handler method with a ConflictResolver as part of the inputs.

`

@CommandHandler
public void onMyCommand(MyCommand command, ConflictResolver resolver) {

}

`

Last but not least, to send a command I did it this way:

`

MyConflictResolver conflictResolver = new MyConflictResolver(eventStore, id, expectedVersion);
DefaultUnitOfWork.startAndGet(null).onPrepareCommit(uow -> conflictResolver.ensureConflictsResolved());
ConflictResolution.initialize(conflictResolver);
commandGateway.sendAndWait(command);
CurrentUnitOfWork.commit();

`

I have absolutely no idea then what to do. In the onMyCommand() method, I keep receiving a NoConflictResolver object instead of a MyConflictResolver.

Even worst, I do not understand the basic principles of the mechanism. In the onMyCommand() method, shall I call the detectConflicts() method or is it done automatically by the engine?

Any help would be much appreciated!
Thanks

You shouldn’t need to inject your conflict resolver in a command handler. At least in 2.x, conflictresolvers are configured on the eventsource repository

`

<axon:event-sourcing-repository conflict-resolver=“templateConflictResolver” id=“templateRepository” … />

`

“templateConflictResolver” is just a Spring bean. In order to let Axon trigger it you need to make sure that your CommandTargetResolver returns also the version (ie the AR sequence number if you want) of the AR that you want to execute your command against. By default this will be the case if you annotate a @TargetAggregateVersion attribute in your command, representing the version.

Hope this gets you going in the right direction, it’s a pretty neat and powerful mechanism once you have it setup correctly.

Jorg

Thanks for the response Jorg but I’m still a bit lost.

Actually, I have taken a look at the DefaultConflictResolver. This class is not instantiated as a Spring bean as the constructor takes in input: EventStore eventStore, String aggregateIdentifier, long expectedVersion, long actualVersion.

I was assuming that an instance of a DefaultConflictResolver is created for each command and that there would be a way to map the @TargetAggregateVersion element of the command to the conflict resolver to manage the conflicts.

If that’s a Spring bean, I just have access to the detectConflicts() method taking a predicate in input. Who’s in charge to fill the actual list of DomainEventMessage then?

I’m kind of lost as you can see :slight_smile:

Hi,

conflict resolution is quite different in Axon 3, than it was in 2. In Axon 2, you have to configure it on the repository. In Axon 3, things are a lot simpler.

I think the reason you’re lost, is because you’re implementing half of the conflict resolution mechanism yourself. Instead of creating a ConflictResolver instance, simply do the following:

  • Make sure your commands contain an @TargetAggregateVersion on a field that identifies the version of the aggregate you expect
  • Make sure your Aggregate is event sourced
  • In the @CommandHandler method signature, add a parameter of type ConflictResolver
  • In the @CommandHandler implementation, register any assertions you have on conflicts.

For example:

@CommandHandler
public void handle(SomeCommand command, ConflictResolver cr) {
cr.detectConflicts(l -> /* check the given list of events for anything you would consider a conflict with this command */);
}

The Conflicts class provides a number of predicates you can use to easily check for events of a certain type, or events of which the payload matched a predicate.

Hope this helps.

Cheers,

Allard

Thanks Allard for the response, I’ll try to come to the 2d workshop in December, this looks great.

- Make sure your commands contain an @TargetAggregateVersion on a field that identifies the version of the aggregate you expect
Checked

- Make sure your Aggregate is event sourced
Did you mean using event sourcing principles with annotated @EventSourcingHandler? If yes this was done as well

- In the @CommandHandler method signature, add a parameter of type ConflictResolver
Checked

- In the @CommandHandler implementation, register any assertions you have on conflicts.
Checked, I implemented a dummy one for my test but for sure at some point, I will use the Conflicts methods.

Meanwhile, I changed the way I was using the uow to this:

`

DefaultUnitOfWork.startAndGet(null);
commandGateway.sendAndWait(command);
CurrentUnitOfWork.commit();

`

Yet in my @CommandHandler method, nothing seems to be triggered. Even though the ConflictResolver implementation is org.axonframework.commandhandling.conflictresolution.NoConflictResolver.

Am I missing something there? Do I need to force something to reference somewhere a DefaultConflictResolver?

Thanks!

Perhaps I was not clear enough. I meant if in the @CommandHandler method I do a cr.getClass() it returns me a NoConflictResolver.

Hi,

Axon uses that implementation in case it didn’t find any events that could potentially be a conflict. This means that either the @TargetAggregateVersion annotated field wasn’t found or didn’t contain a value, or otherwise that the value for @TargetAggregateVersion was equal or higher than the actual version of the aggregate that was loaded.

It seems that you’re expecting at least one event that is a potential conflict. If you set a breakpoint in AbstractRepository.load(String Long) (line 108 in recent versions), you can inspect the actual values of the load() invocation. The second parameter should be a non-null value. Alternatively, you can check the AnnotationCommandTargetResolver (resolveTarget method) for the actual values of the identifier and version that it found.

Hope this helps.

Cheers,

Allard

Hi Allard,

I am confused here…

If I simply my implementation it looks like this:

`

@CommandHandler
public void onMyCommand(MyCommand command, ConflictResolver cr) {
try {
Aggregate agg = repository.load(id, new Long(command.getExpectedVersion()));
//Update aggregate
} catch (AggregateNotFoundException e) {
//Create aggregate
}
}

`

I changed to call the method load(String, Long) instead of load(String), I guess it was a mistake, thanks for that.

Yet if I do a cr.getClass() I still get a NoConflictResolver implementation and I still don’t understand what shall I do now…

What is the value of getExpectedVersion() (in the command) and what it the value returned by the “version()” method on your aggregate?

Allard

I try to generate a conflict on purpose.
The getExpectedVersion() of the command returns 0 whereas the version() of my aggregate is 1.

It generates the following error:

`
by: org.axonframework.commandhandling.model.ConflictingAggregateVersionException: The version of aggregate [x2] was not as expected. Expected [0], but repository found [1]

`

That makes sense but I got the very same error if I call the load() method without providing a ConflictResolver the my @CommandHandler method.
I really don’t see how the conflict resolver could automagically be triggered here. Before to dig into the @CommandHandler method, Axon could now what’s the expected version (from the command/@TargetAggregateVersion) but it does not know which aggregate I will load then…

Sorry, it took a while to figure it out, but the ConflictResolver on an @CommandHandler only works if the @CommandHandler annotation is placed on a method in the aggregate itself. That’s because, upon invocation of your @CommandHandler method, Axon doesn’t know yet what you’re trying to load.

The ConflictResolution API wasn’t designed with this specific use case in mind, but there is a workaround to get hold of the ConflictResolver instance. However, this will only work after loading the aggregate with the correct “expectedVersion”.
Simple do: new ConflictResolution().resolveParameterValue(CurrentUnitOfWork.get().getMessage()); to get hold of the ConflictResolver instance.

I will add a (static) method to the ConflictResolution class to make is somewhat easier to use in 3.0.7.

Cheers,

Allard

Thanks Allard for the help.

Yet, when I call the repository.load(string, long), regardless if I do your trick to retrieve a ConflictResolver instance or not, it always fail because of:

`
The version of aggregate [x39] was not as expected. Expected [0], but repository found [1]

`

Meanwhile, if I set a @CommandHandler on my aggregate, it will fail if the aggregate is not found (for a creation for instance)…

I’ve just implemented a little test scenario, where I load an Aggregate with an expected version lower than the actual. Then, when I do a detectConflicts(t -> false), no Conflict is raised. If I don’t do that, it raises a Conflict, as expected.

Note that the predicate should return true when there is a conflict. Are you sure you invoke detectConflicts with the proper Predicate?

Regarding your @CommandHandler method on the Aggregate itself, the creation handler must be a Constructor. If the annotation is put on an instance method, it expects an instance to be available.

Cheers,
Allard

Sorry for the delay I was out of office for a week.

Thanks a lot for your answer now I am able to have something working. Yet I can see some conflicts with my current implementation.
Actually, I already manage optimistic versioning with my event store (based on an expected version). What I would have expected is to implement the following sequence:

  • Try to insert an event
  • If it failed due to a versioning error, triggers the conflict management system to actually check whether the event was a “real” conflict with the sequence of events since the expected version
    Shall I try to play with uow.OnRollback() then?

Hi Teivah,

I think you’re mixing up two types of conflicts here.

  • concurrency exception is when two processes will simultaneously attempt to insert an event with the same sequence numbers. This effectively means that the second command didn’t run on the state that the first command had left. Therefore, there is a conflict. It is safe to retry a command after this exception.
  • conflicting modification exception is when you have indicated which version of an aggregate you expect, but got another one (usually more recent). That effectively means that things have happened that a user did not take into account when making a decision. It is up to the ConflictResolver to indicate whether any unseen changes represent a conflict given the current intent of the user.

In other words, Conflict Resolution will only help you in the second case, In the first, simply retry the command to execute it on the latest state of an aggregate.

Hope this helps.
Cheers,

Allard

Hi Allard,

Just a confirmation if possible that my implementation is the correct one.
First off, bear in mind my command handlers are implemented outside of the aggregate (because I wanted for the same command to either create an aggregate if not existing or update an existing one).

I simply put something like this after having loaded the aggregate (without providing the expected version):

`

if (expectedVersion != null) {
final Predicate<List<DomainEventMessage<?>>> listPredicate = a -> false;
final DefaultConflictResolver cr = new DefaultConflictResolver(eventStore, id, expectedVersion, agg.version());
cr.detectConflicts(listPredicate);
CurrentUnitOfWork.get().onPrepareCommit(uow -> cr.ensureConflictsResolved());
}

`

In this example, I return a constant false just to make sure the command is handled even though the expectedVersion does not match the currentVersion.

I understood this was the only way to do it because once again, my command handler is outside of the aggregate. Am I correct?

If yes, don’t you think it would make sense to add a method to the Repository interface to encapsulate such logic? Something like:

Aggregate<T> load(String aggregateIdentifier, Long expectedVersion, Predicate<List<DomainEventMessage<?>>> predicate)

Or perhaps somewhere else because I guess the conflict resolver mechanism is only useful in case of the repository instance is an EventSourcingRepository one? That’s just a proposition because I lost some hours to find the solution ^^.

Hi Teivah,

I’ve actually never tried using the ConflictResolver outside of the aggregate, but this should be possible as well:

@CommandHandler
public void handle(Command cmd) {
Aggregate repository.load(cmd.getId(), cmd.getExpectedVersion());
ConflictResolution.getConflictResolver().detectConflicts(…);
}

The EventSourcingRepository uses the UnitOfWork to register a ConflictResolver. The ConflictResolution class then takes it out of there.

This should be simple enough, right? Perhaps, in future releases, we could expose potential conflicts as part of the Aggregate interface, instead of via the UnitOfWork. This was an approach that was fully compatible with existing APIs.

Cheers,

Allard

Oh I confirm this works!
You rock :wink: