Eventual Consistency

How do axon based projects approach the problem of eventual
consistency between the domain and the query model. From my
understanding of CQRS is that command should be pre-validated against
a query model by the client before command is submitted to the command
bus to give the command the best possible chance of succeeding.

So the question is are there any best practices for handling the case
where the command is prevalidated and then fails when it is processed
by the command handler. Perhaps the best example here is when the
aggregate version is incremented. Two user submit commands within a
close enough time frame that the query model has not been updated yet
to indicate that the data has been changed by someone else. Assuming
that I cannot resolve the conflict with a conflict resolver.

I have read a bit about conpensating logic but I am struggling with
the case where the user think they have successfully change the domain
with a command but the command acutally fails when it processed. They
then continue to make further changes based on the assumption that the
first command worked.

Hi

You cannot validate against de query model, because there’s a one-to-many relationship. A commando can have effect on multiple query models.

So validation should be done on the commandmodel.

That said, the sample application shows a workaround. If I remember correctly, it uses a querymodel to place a lock. You’ll have to use transactional boundaries to clean then up though.

Regards
Roald

Hi,

Roald, that’s not entirely true. It is very much possible to validate against “a” query model. In fact, based on information in your UI, you (or the machine) validates that a certain action can be taken. For example, it is useless to confirm an Order, if the query model already says the order is shipped and closed. The point of prevalidation is to not bother your user with options and buttons that fire commands that don’t make sense given the current state of things. However, since things change (we live in a concurrent world), what makes sense at a certain time, might not make sense anymore after 2 seconds, because another user has changed state. The UI will not immediately reflect that change and allow the user to submit “invalid” commands.

Sheak, to answer your question: there are several approaches when it comes to consistency. But your problem isn’t so much related to consistency, but more with dealing with concurrency and data staleness.

The best thing to do is to make sure commands can’t ever have a “negative” outcome. A failed command can only occur when two users simultaneously do something, without them knowing. Even with full consistency, one of the users will end up with a situation he didn’t expect. Preventing negative outcome is not easy, but certainly far from impossible. Udi Dahan is a proponent of this approach.

There is also a middle road: make command execution synchronous (i.e. your client will wait for the execution of a command). Command execution is done against a fully consistent model. Axon can make sure the necessary locks are in place (LockingRepository). If state has been changed by another user, you can use the conflict resolver to try to resolve the conflict. If that’s not possible, your client is still around to let him know his request was refused. A good client will update his view model and see a state that explains the failure of his command (e.g. somebody must have already approved the Order).

The ultimate form of consistency is to execute all event handlers within the same transaction that was used to update the command model. This approach severely limits scalability. And although it seems that everything is consistent at all times, don’t fool yourself here. Concurrent access to the application will still yield “stale” data from your query model. Data consistency is not a solution for data staleness.

So, where possible, I try to use the first approach. However, I let my clients wait for successful execution of a command. When something is wrong (which for some reason, I call him Murphy, always happens when least expected), you have the chance to notify the client.

Hope this answers your questions.

Cheers,

Allard

Hello,

Here is a practical example where a unique check is done on the
command server:

http://code.google.com/p/axon-auction-example/source/browse/trunk/auction-command-server/src/main/java/org/fuin/auction/command/server/base/AuctionCommandHandler.java?r=181

Method: handle(CreateCategoryCommand)
Line: constraintSet.add(categoryName);

This call checks if the category name is unique and throws a
CategoryNameAlreadyExistException otherwise.

In other cases it should be possible to execute a query but I found
this difficult for cases when a unique key constraint needs to be
enforced.

Cheers,
Michael

Thanks for all the feedback I think I understand how to handle the problem. I will make sure the command response is received by the client to guarantee that the command was successful.

Hey,

I first wanted to nitpick why you used...

                if (LOG.isDebugEnabled()) {
                        LOG.debug("Handle command: " +
command.toTraceString());
                }

Using a log4j pattern in a slf4j logging statement. Then I saw your
toTraceString() method. Now I believe slf4j is missing a jsp like
syntax to be even more usefull:

LOG.debug("Handle command: ${param[0].toTraceString()}", command);

So who is going to make tnslf4j? (The NEXT simple logging facade for
java) :slight_smile:

Back on topic...

What facility does axon offer in case of a distributed system where
you needs to check a constraint over everything in in the cluster.
IMHO you cannot guarantee at the dispatch of the command or the
handling of the command that consistency. You CAN however guarantee
that the "action" is being processed.

Suppose you have a command where you register a globally unique
username. You cannot guarantee to catch the problem of 2 actors
registering the same username at the same moment. You can create a
"GlobalUsernameRequestInProcess" that after some time where no other
username requests with the same name are submitted can conclude that
the username is indeed unique.

I do presume the most paranoid case of a clustered environment with a
non-ACID 'eventually consistent' datastore like cassandra.

btw... When will 0.7 be stable?

A saga would a fit for the above use case of handling the
"GlobalUsernameRequestInProcess".

Hi Jaron,

the consistency discussion is one that pops up every now and then. For some reason, the use of CQRS makes people wonder. The nice thing (or actually the painful reality) is that the project is related to scalability (cap theorem) in the first place.

Here is a thread that show a similar discussion. You might find your answer here: http://groups.google.com/group/axonframework/browse_thread/thread/c154bd43b681b0c/

The first question you should (always) as is: “so what if…”, and in this case “so what if we have two identical usernames”. You should always check the business impact first. If the answer is “we’d be out of business”, then a solution like you describe (making user account creation a process) could be a possible answer.

About slf4j… I hope you understand that I consider changing the logger API out of scope. :wink:

I’m trying to get 0.7 out this year. There is still dome work to do, but I might make it.

Cheers,

Allard

The short answer is that axon does not create consistency problems nor
does it solve existing consistency problems.

But maybe the confusion comes from the filesystem eventStore in axon
and that there is no clear example of a clustered axon setup.

Hi Jaron,

the consistency discussion is one that pops up every now and then. For some
reason, the use of CQRS makes people wonder. The nice thing (or actually the
painful reality) is that the project is related to scalability (cap theorem)
in the first place.

Here is a thread that show a similar discussion. You might find your answer
here:http://groups.google.com/group/axonframework/browse_thread/thread/c15

The first question you should (always) as is: "so what if...", and in this
case "so what if we have two identical usernames". You should always check
the business impact first. If the answer is "we'd be out of business", then
a solution like you describe (making user account creation a process) could
be a possible answer.

Indeed you could always handle it with the "bad luck" pattern. The
second guy looses during the phase where eventual consistency makes it
apparent there is a conflict.
How you handle it is indeed a business choice.

<http://groups.google.com/group/axonframework/browse_thread/thread/c15...&gt;About
slf4j.. I hope you understand that I consider changing the logger API out of
scope. :wink:

That was just a brainfart...

I'm trying to get 0.7 out this year. There is still dome work to do, but I
might make it.

Is it "There is still SOME work to do" or "There is still DAMM work to
do"?

Cheers,

Allard

> Hey,

> I first wanted to nitpick why you used...

> if (LOG.isDebugEnabled()) {
> LOG.debug("Handle command: " +
> command.toTraceString());
> }

> Using a log4j pattern in a slf4j logging statement. Then I saw your
> toTraceString() method. Now I believe slf4j is missing a jsp like
> syntax to be even more usefull:

> LOG.debug("Handle command: ${param[0].toTraceString()}", command);

> So who is going to make tnslf4j? (The NEXT simple logging facade for
> java) :slight_smile:

> Back on topic...

> What facility does axon offer in case of a distributed system where
> you needs to check a constraint over everything in in the cluster.
> IMHO you cannot guarantee at the dispatch of the command or the
> handling of the command that consistency. You CAN however guarantee
> that the "action" is being processed.

> Suppose you have a command where you register a globally unique
> username. You cannot guarantee to catch the problem of 2 actors
> registering the same username at the same moment. You can create a
> "GlobalUsernameRequestInProcess" that after some time where no other
> username requests with the same name are submitted can conclude that
> the username is indeed unique.

> I do presume the most paranoid case of a clustered environment with a
> non-ACID 'eventually consistent' datastore like cassandra.

> btw... When will 0.7 be stable?

> A saga would a fit for the above use case of handling the
> "GlobalUsernameRequestInProcess".

> > Hello,

> > Here is a practical example where a unique check is done on the
> > command server:

> >Google Code Archive - Long-term storage for Google Code Project Hosting.

> > Method: handle(CreateCategoryCommand)
> > Line: constraintSet.add(categoryName);

> > This call checks if the category name is unique and throws a
> > CategoryNameAlreadyExistException otherwise.

> > In other cases it should be possible to execute a query but I found
> > this difficult for cases when a unique key constraint needs to be
> > enforced.

> > Cheers,
> > Michael

Happy christmas...