DDD and CQRS – How to Handle Post-Validation Errors in Command

cqrsdomain-driven-designerror detectionerror handling

For example, when you submit a Register form, you have to check in the Domain Model (WriteModel in CQRS) that it is in a valid state (example, email address syntax, age, etc).

Then you create a Command, and send it to a Command Bus.

I understand that Commands should not return anything.

So how do you handle an error beyond Command Bus? (For example, a user registered 1 second before with the same username/email).

How do you know that command failed, and how do you know the error?

Best Answer

I understand that Commands should not return anything.

That's one view, but it's not entirely set in stone. Consider writes (PUT, POST, DELETE) in HTTP -- all of these messages are commands, in the sense that they are messages with request that the resource change state, and yet they all return responses.

So how do you handle an error beyond Command Bus? (For example, a user registered 1 second before with the same username/email).

How do you know that command failed, and how do you know the error?

So in a case where you are communicating directly with the command handler, a returned message is a perfectly reasonable way to acknowledge that the command has been received and processed.

If you are using a piece of middleware, like a bus, that prevents you from communicating directly with the target, then I would suggest that you look to asynchronous messaging patterns -- how do you get the command handler to send a message back to the caller?

One idea is to subscribe to the outcome of the command; this borrows from some of the ideas in Hohpe's Enterprise Integration Patterns. The basic idea is that, since the client is familiar with the command message that was sent, it is well positioned to subscribe to any new messages published as a consequence of the command message. The command handler, after saving the data to the book of record, publishes events announcing that the change was successful, and the client subscribes to those events -- recognizing the correct events by considering the coincidence of various identifiers in the message (causation id, correlation id, and so on).

Alternative approaches are a bit more direct. One would be to include in the message a callback, which can be invoked by the command handler after the message is successfully handled.

An very similar alternative is to reserve space in the command message for the command handler to write the acknowledgement -- since the client already has the command message in question, the circuit is already complete. Think "promise" or "completable future". The message tells the command handler where to write the acknowledgement; doing so signals to the client (countdown latch) that the acknowledgement is available.

And of course, you have the additional option of removing the middleware that seems to be getting in the way of doing the right thing simply.

For example, a user registered 1 second before with the same username/email

If you are handling user registration idempotently, that wouldn't necessarily be an error -- repeating messages until a response is observed is a common way to ensure at least once delivery.