How do you tell the sender why the command failed or was rejected?

793 views
Skip to first unread message

Stefan Moser

unread,
Jun 2, 2011, 5:51:58 PM6/2/11
to ddd...@googlegroups.com
Commands can fail or be rejected.  How do you tell the sender why the command failed or was rejected?

Example: Book store, the command is PurchaseBook and it gets rejected because the book is out of stock.  The UI has a requirement to tell the customer that the order did not complete because the book was out of stock.  There are a couple of options that I can think of.
  1. The commands are processed synchronously and return a "command result" object to the sender.  The command result would contain success/fail and some sort of structure why the command failed.  I don't mind this option, but I think it's a slippery slope to CQRU (command query responsibility unification) where developers start stuffing what are essential query results into the command result object.
  2. The domain produces an event FailedToFullfillOrderDueToOutOfStock that doesn't change any state in the domain, but is published on the event bus.  The UI could then register to the event bus, or issue a query to the read model to find out why the order failed to complete.  If the UI issued a query, then the read model would have to create a model of orders that never actually got created.
I'd like to hear how people solve this problem.  Discuss.

Cheers,
Stefan

Greg Young

unread,
Jun 2, 2011, 5:53:50 PM6/2/11
to ddd...@googlegroups.com
HTTP status codes can work well

--
Les erreurs de grammaire et de syntaxe ont été incluses pour m'assurer
de votre attention

Shawn Hinsey

unread,
Jun 2, 2011, 5:56:43 PM6/2/11
to ddd...@googlegroups.com
I return a command publication record rather than a command result for
asynchronous operations. This includes an identifier that I can use to
query a command registry. If a command fails, the registry would
indicate this and provide a URL for a more detailed error object on
the data bus. There are a lot of cases where this pattern can make
sense for error-free scenarios as well.

On Thu, Jun 2, 2011 at 5:51 PM, Stefan Moser <stefan...@gmail.com> wrote:

Greg Young

unread,
Jun 2, 2011, 5:58:24 PM6/2/11
to ddd...@googlegroups.com
async is prefered.

--

João Bragança

unread,
Jun 2, 2011, 9:07:13 PM6/2/11
to ddd...@googlegroups.com
+1 to this. Return 202 Accepted and a Location header that tells the UI where to poll the read model for the result. If you are using async and the handler / domain object throws an exception you will have to publish an event also.

Udi Dahan

unread,
Jun 3, 2011, 3:54:54 AM6/3/11
to DDD/CQRS
The client would check stocking levels before submitting the purchase
command.

As a result, the only reason a command would "fail" would be a race
condition and, as I mentioned in my blog post Race Conditions Don't
Exist (http://www.udidahan.com/2010/08/31/race-conditions-dont-
exist/), that indicates some deeper business analysis is needed.

In short, we'd decouple the business relationship between purchasing,
billing, and inventory/shipping.
As a result, the command could still be async/one-way because it never
really fails after its sent.

Cheers,

-- Udi Dahan


On Jun 2, 11:51 pm, Stefan Moser <stefan.mo...@gmail.com> wrote:
> Commands can fail or be rejected.  *How do you tell the sender why the
> command failed or was rejected?*
>
> Example: Book store, the command is PurchaseBook and it gets rejected
> because the book is out of stock.  The UI has a requirement to tell the
> customer that the order did not complete because the book was out of stock.
>  There are a couple of options that I can think of.
>
>    1. The commands are processed synchronously and return a "command result"
>    object to the sender.  The command result would contain success/fail and
>    some sort of structure why the command failed.  I don't mind this option,
>    but I think it's a slippery slope to CQRU (command query responsibility
>    unification) where developers start stuffing what are essential query
>    results into the command result object.
>    2. The domain produces an event FailedToFullfillOrderDueToOutOfStock that

Tom Janssens

unread,
Jun 3, 2011, 9:37:50 AM6/3/11
to ddd...@googlegroups.com
As a result, the only reason a command would "fail" would be a race
condition and, as I mentioned in my blog post Race Conditions Don't
Exist (http://www.udidahan.com/2010/08/31/race-conditions-dont-
exist/
), that indicates some deeper business analysis is needed.



Interesting read; Thanks Udi !

John Nilsson

unread,
Jun 3, 2011, 7:45:41 PM6/3/11
to ddd...@googlegroups.com
I would be very interested in examples of how people handle that
particular issue. Given the requirement that a customer should not be
able to place an order thinking that the product is in stock how do
you handle out of stock situations asynchronously?

BR
John

João Bragança

unread,
Jun 3, 2011, 7:57:11 PM6/3/11
to ddd...@googlegroups.com
I used to do development at an import export company. We *never* prevented the customer from ordering. We just used his payment to put a down payment on our next order from the supplier.

You won't be able to handle this asynchronously. Or you can change the requirement and allow customers to order stuff that isn't in stock. Then they get an email later that says 'oops!' and that part of their order is cancelled.

kjetilk

unread,
Jun 4, 2011, 5:03:59 AM6/4/11
to DDD/CQRS
Saying that a command will never fail is at best a very naive
consumption. It might not fail because of broken business rules, but
there's a lot of infrastructure that can couse failure (webserver,
iis, ms dtc, msmq, esb,...).

And even though you're able to get the command across the wire and
persist it on the command side before anything goes wrong (so that
will be able to replay it successfully later), from the users
perspective it is a failure when the result doesn't show up on the
read side within a reasonable timespan. So yes; you should definetly
handle failures.

The way we're implementing failures on the command side is by giving
every command an unique id (a Guid) on the client. When the command is
sent (on a background worker thread) the client will start polling the
query-side for a status on the given command. When the command is
received on the command side it will first try to persist it locally
and the trigger the command handler to do it's work. Since the command
is sent on a background thread from the client, we can afford to do
this synchronously. That is; the client will wait for a "202 Accepted"
from the command server, knowing that the command has been handled
without errors and the event(s) has been published and put out on the
bus. After the command handler has finished (and publised it's domain
events), a 'CommandSucceededEvent' will be published as well
(containing the command guid from the client) if the command actually
succeedes. Else there will be a 'CommandFailedEvent' with a
description of the failure and the same id. This event will be put on
the query side so that the client can get the status.

If the client finds the 'status ok' for the comand on the query side,
everyting is fine and dandy. If it's an error message, display it to
the user in a friendly manner and let the user deceide if this is
something (s)he can do anything about. If there's no message available
withing a "reasonable time" (configurable, and potentially elastic
based on the current load on the server), it's also considered a
failure. Hopefully we were able to persist the command before the
incident and we can take action (try again, debug,etc).

Off course, I'm not saying that this is the ultimate solution for
everyone, but it's a solution that works well for us.

sincerely,

Kjetil Klaussen

Sebastian Burgstaller

unread,
Jun 4, 2011, 6:47:51 AM6/4/11
to DDD/CQRS
Hi Kjetil!

So you are persisting commands too?
Is this a common/recommended practice, to have a "command store" AND
an event store?

Cheers,
Sebastian

kjetilk

unread,
Jun 4, 2011, 8:23:13 AM6/4/11
to DDD/CQRS
Yes, we're persisting commands in case of failure and to have the
possibility to replay the command if there's a bug or infrastructure
failure during command execution. It also gives us a way to track how
long commands use to get from the client to the query-side, since
we're putting timestamps both on the time when it's sent from the
client, when it's received on the command side, when it's been
processed by the domain model, and when the CommandSucceededEvent/
CommandFailedEvent arrives at the query side. That way we can data
mine the time taken and do performance optimization based on where the
real bottlenecks are in the system are. If customers complain about
things beeing slow, we're also able to see whether that's caused by
network latency between the client and server (meaning; not our
fault...) or whether it's somewhere on the server side.

We're not using event store (ES), though. We're using a more 'classic'
approach to the domain model and using EF code first to store domain
model state in a SQL Server.

If this is a common approach (storing commands), I have no idea. Other
users on this forum might tell whether their doing something similar
or not and thereby give a hint of the 'commonality' of this, but other
than that I highly doubt there's any statistics available on this
matter :)

sincerely,

Kjetil Klaussen



On Jun 4, 12:47 pm, Sebastian Burgstaller <sburgstal...@gmail.com>
wrote:

Udi Dahan

unread,
Jun 5, 2011, 8:17:08 AM6/5/11
to DDD/CQRS
A proper ESB (like NServiceBus) handles all kinds of infrastructure
failures such that the command will eventually succeed.

There are other ways to architect the user experience such that you
don't need to poll the read side. Consider the Amazon.com shopping
cart - after adding something to your cart, they usually don't show
you your cart, but rather all the other things you should add to your
cart as well.

Cheers,

-- Udi Dahan
> > > Stefan-הסתר טקסט מצוטט-
>
> -הראה טקסט מצוטט-

Nuno Lopes

unread,
Jun 7, 2011, 12:44:26 PM6/7/11
to ddd...@googlegroups.com
Let' the user place the order yet subject to confirmation.

Cheers,

Nuno

kjetilk

unread,
Jun 7, 2011, 4:05:28 PM6/7/11
to DDD/CQRS
Yes, in this specific example (purchasing a book) I agree that this
would be a valid way to handle it the "amazon way".

However, I was more refering to the general handling of commands in a
LOB application, so I guess my answer was a bit out of context here.
Sorry about that :)

-kjetil

Greg Young

unread,
Jun 7, 2011, 4:38:38 PM6/7/11
to ddd...@googlegroups.com

Part of the joy is trying to get your lob app to work that way :)

kjetilk

unread,
Jun 8, 2011, 3:45:10 PM6/8/11
to DDD/CQRS
Yes, if only we were building a web store of some kind... Truth is
that I can't really see the harm in giving our end user some
information if a command for some reason will take more time than
expected to travel through the domain model and populate the read side
thrugh events.Wouldn't you as a LOB user appreciate such feedback?

Be aware that I'm not talking about explaining the concepts of
'eventual consistency' back to user here. Users will be trained to
accept that their client side data will take some time to be updated.
I'm talking about the cases were the 'eventual' part becomes far
longer than expected. Say that from measures we know that the average
time for a comand will be 3 seconds and the normal distribution tells
us that the 90 percentile is within 4.5 seconds on the high side. If
the comand takes more than 30 seconds we can be pretty sure that
something irregular is going on. Wouldn't it be nice to give the user
some confirmation that 'yes we received your command and we will
handle it, but currently something fishy is going on so it might take
a while before you'll be able to see it'? And the irregular part here
can be anything from a bug (yes I know; we're writing unit test so
bugs doesn't exists, right? ... errrr....), infrastructure failure,
maintance, hardware failure, you name it. If it can happen, it will
happen.


-kjetil



On Jun 7, 10:38 pm, Greg Young <gregoryyou...@gmail.com> wrote:
> Part of the joy is trying to get your lob app to work that way :)
>

Nuno Lopes

unread,
Jun 9, 2011, 5:09:48 AM6/9/11
to ddd...@googlegroups.com
On "asynchrony".

Warning: Common sense ahead ...

In programmers language the concerns at hand are in the realm of algorithms. Given a problem with at least one solution, It's our job to to find out what can be computed in parallel and what can't and this includes things such as business process.

In high technically matured companies, when we have technical concerns intersecting business concerns, a problem is not simply given to a an architect or programmer living in a bunker. Indeed, neither architects or programmers in these kind of institutions usually live in bunkers (I've seen some places where entire IT departments where actually bunkers).

You need to put brilliant people good with algorithms talking with the business. Unfortunately the kind of people needed for this task is extremely difficult to find.

But an opportunity for parallelism does not imply an opportunity for improving system performance. What? Yes, you heard in this forum at least from ME.

There is plenty evidence out there in the world about this. But if one needs one right now read a very old book "The Mythical Man-Month".

What does this have to do with algorithms, domain driven design and OO? Well, one man is an Object.

So here is the drill. Don't copy Amazon processes to your context! That is impossible. Instead only try to realize the truth, there is no Amazon.

I'm sure someone from DDD-CQRS will write a blog post in the same tone in a few months, and it will get re-tweeted all over the world as a perl of thought ...

Cheers,

Nuno

Reply all
Reply to author
Forward
0 new messages