Posts
1150
Comments
891
Trackbacks
1
cqrs for dummies – 2.1 of n – command layer notifications

And so of course, I managed to leave out one important consideration.

You are on the UI and you, e.g., click a button that creates a command.  What happens now?

I didn’t really talk about either the command bus or the command handler, because to a certain extent they are implementation details.  You could actually have, e.g. NServiceBus and use a bus, or you could connect through regular method calls, or you could do a host of different things.  When it comes to the command handler, you could have some generic handler class or, better I think, have a one-to-one pair between a command and a handler (quick note below).

More important is the question, what do you do if the command fails?  With CQRS, even more important to answer is the question, what do you do if the command succeeds?

Command Notification

One set of validation failures can be handled at the client before a command is sent, and the ways of accomplishing this are as varied as they are when CQRS isn’t involved (in fact, CQRS doesn’t change a thing here).  Field length validations, regex validations, required field validations, etc. are all things that can be handled by javascript, view model annotations, or a host of other solutions.  I won’t go into any more detail here, other than that you would notify the UI when this occurred.

Another set of notification failures are ones that happen due to technical problems with the command bus and/or command handler.  These are almost all implementation specific, and so I don’t really have a lot to say here that would be useful (again, you would notify the UI per usual here).

The next set of notification failures are due to a command passing all local validation and then being passed through the bus/handler and into the domain, and then failing due to whatever reason (could be technical problems, could be failing domain-side validation, doesn’t matter).  How do you handle this?

It depends a little bit on whether you handle your commands in an async manner or not.  Normally, I wouldn’t use async methods here, and instead either make your command passing methods return true or false, or throw a specific exception on why the command failed to be processed inside the domain (this is in my mind preferable, so that you know what to due in various situations).

digression: in case there is any confusion, when I talk about a command failing to be processed in the domain, this shouldn’t be thought of as an ‘exceptional’ in the sense of being rare.  I know there is a lot of ‘religious’ debate around exceptions, and in other contexts, I would argue that throwing an exception for a scenario that isn’t rare is arguably bad design.  In this situation, if a command fails to be processed inside the domain, I want to know why.  Did it fail because of some specific validation rule within the domain?  If so, which one?  If not, was it a technical problem?  Methods that return true/false don’t give you this level of detail.  I suppose that one could return a ISpecificCommandSentToDomainMethodResponse message back to the UI.  This might actually be a better option.  But I digress.

The really interesting case is when you send a command that succeeds, in the scenario where you are using Eventual Consistency.

Keep in mind that you can have a separate Event Store and a separate Query Store, and have all communications between them take place with full transactional support.  Though my guess is most implementations of CQRS in the wild will have some amount of Eventual Consistency built in, it isn’t, strictly speaking, required.

But what if you are using Eventual Consistency?  This raises interesting scenarios.  I’m the customer updating my Address through the UI and click the update button.  If I’m using Eventual Consistency, the UI screen will return after the command is sent and doesn’t fail (since we don’t know how long it will take till the query store gets updated, we don’t want to block once the command makes it through the domain).  What do we show the user?

There are a couple of options, and a lot of it depends on context and what the end user expects.  An obvious option for commands that might reasonably be expected to take more than a few milliseconds is to simply tell the user that the request has been submitted, and to check back later.  Though I don’t have any personal experience in the area, I’ve heard anecdotal reports from many people who use online banking and expect this sort of behavior. 

In other cases, you can, well,….’lie’ to your user.  The end user sent the information that they wanted to update, so it is available on the client (cached or in session or whatever), so you can redraw your UI to include this info.  By the time the end user gets into a scenario where they actually have to re-query the Query Store, the info will be there by then.

Mark and Udi have suggested techniques such as these, and while I admire the cleverness of them, I don’t like them.  If an end user expects some end result and is shown a ‘fake’ and then, for whatever reason, that end result doesn’t end up in the query store….that seems bad to me.  I suppose, like everything, it depends on context.  If one is using an internal system and it happens once in a blue moon, and there is a well understood set of actions an end user can take, maybe that’s all right.

But, in general, I lean toward the ‘you sent a command, check back later’ model.  It’s honest, and publicly understood.

Command Handlers

Why would it be better to have a specific command handler per command, especially if command handlers are implementation specific anyway?

Potential scalability.  If I have a separate piece of code, say, CommandXHandler, to handle all instances of CommandX, then, there is a potential there that I can take that piece of code (CommandXHandler) and scale it separately if needed.  For instance, suppose I use MSMQ and so my command bus is MSMQ and different handlers are different queues.  Suppose it turns out that a certain type of CommandX is more prevalent than others.  If needed, I could then dedicate separate hardware to handle these commands apart from the rest.

posted on Monday, March 15, 2010 11:38 PM Print
Comments
Gravatar
# re: cqrs for dummies – 2.1 of n – command layer notifications
Peter
3/16/2010 9:35 AM
Like you, showing a 'fake' view to the user just seems wrong. I'm not sure why Udi has presented this as a noble lie. I'd lean towards a 3rd option. Show them the result if it's available. This would be a "status view" just like checking on your order status on Amazon. If the command has propagated, great, tell the user. If not, show a message that the request was submitted and is being processed. In either case, send an email (if appropriate) with a link to the status view. Of course, this all presumes that the command is successfully submitted and all you're waiting on is data propagation. I'd want to see the typical latency for my reporting store to be in sync with my commands because this approach starts to interfere with user experience if every little update requires a status page.
Gravatar
# re: cqrs for dummies – 2.1 of n – command layer notifications
jdn
3/16/2010 6:44 PM
@Peter

One potential issue with this 3rd option is that you would have to query both the query store and the event store to know if a request was submitted (since if the query store already knew this, it would already know the result). Whether this is a real issue or not is, of course, context-dependent.

When I think about potential issues like this, I think back to the high traffic events that I dealt with when a part of the team that ran the eCommerce stores for Nascar, NBA, NHL, etc. These are the times when Eventual Consistency would have really helped on the query side, and when I wouldn't want to query the Event Store at all, since I would want that store to be devoted solely to getting customer credit card information.

I think that it is best to have the command submission in a transaction so that the only thing you wait on is the data propagation.

Depending on the situation, I think that the overall latency should be pretty low. Even using SQL Server 2000 replication, data propagation was pretty fricking (technical term) fast, and so I think it would be even better today.

Thanks for the comment.

Post Comment

Title *
Name *
Email
Url
Comment *  
Please add 7 and 7 and type the answer here: