the locking strategy in the repository is slightly different from the optimistic strategy you can achieve by supplying the version-known-by-client.
What the repository does is the following:
- two commands load an aggregate simultaneously. If the strategy is optimistic, both threads will recieve a copy of the aggregate.
- thread 1 makes a change, and stores the aggregate, changing it to V+1
- thread 2 now makes a change and stores is too. Since it has based the changes on V, the repository will throw a ConcurrencyException. The command may be retried.
If the strategy was pessimistic, thread 2 would hold at the repository.load(), until thread 1 has made the changes.
The locking strategy in the repository is just a way to guarantee that all changes are applied sequentially on every aggregate.
The concurrency control by using the version supplied by the client is a little different. It is of a more functional nature. What do you want your application to do when an aggregate has been changes by another process while you were looking at your screen, taking a decision?
Here is a scenario:
- user 1 loads a screen showing an aggregate V=0
- user 2 also looks at that screen
- user 1 sends a command to it. Since there are no concurrent modifications (yet) it is changed to V=1
- user 2 also makes a change to modify it.
Now, two things can happen. First, let’s assume we don’t have any conflict resolvers.
- the command given by user results in a ConflictingModificationException when it tries to load the aggregate, since it expects to execute a command on V=0, but was 1.
The other scenario is when you do have a conflict resolver applied.
- the command will load the aggregate, but will internally mark it as “potential conflict”
- the command will apply changes on the aggregate, changing it from V=1 to V=2.
- before committing the aggregate back to the repository, it will verify that the “unseen” changes V=0 to V=1 do not conflict with the newly applied changes V=1 to V=2. The conflict resolver makes this decision.
As you can see the two mechanisms serve a rather different purpose. The locking mechanism of the repository being purely technical (making sure changes are applied sequentally at all times), and the client-known-version mechanism is more functional: “do you want a user to be notified when another user did something he hasn’t seen?”.
Usually, a question if this sort is a good indication that something isn’t clear in Axon. How can I make this distiction in mechanisms more clear? Would it help if I were to change the name of the mechanism in the repository to “ConcurrencyControl”, or something similar?