Examples of error handling (validation and bus rule)

Hi, In looking at the axon-trader and addressbook, I don’t see much (I may be missing it) in the way of practices/approaches to error handling, especially in the round trip sense. It’s my understanding that sending command should be more or less a fire and forget operation. So I’m trying to understand the best way to handle errors, etc. My current arch is something like

Web Page -> REST Api -> Application Service -> commandInvocation (via CommandBus) -> commandHandler/domainInvocation

So currently I just return a 200 to the client when the application service returns after firing off the command. On the happy path, I just go look at the view/read model. It’s not clear to me a) how to handle validation exceptions b) if I pass validation, and say my aggregate method emits a “BadThingHappenedEvent” as opposed to a “GoodThingHappenedEvent”, i’m not sure of the best way to get these issues (a or b) back to the client (if necessary)

Hi Erich,

as always in DDD / CQRS related scenarios, it all depends on the details. But here are some sensible default ways to deal with this.

The CommandBus allows for Interceptors to be configured. Some of these interceptors run in the calling thread, some others in the executing thread. In case of the SimpleCommandBus, the calling thread and executing thread are the same. The main different is that the first type of interceptors is execute before the method returns, allowing them to throw an exception, which is propagated to the caller. This is typically the place where you do structural validation. Your rest API can translate this exception to a 40x error.

As for command handling, when some business rule is violated, you can either throw an exception or use a return value to indicate success/failure. In your rest API, you can deal with this in 2 ways: return immediately giving a 302 while providing a URL where the client can request the result (as soon as it is available). Alternatively, you can wait for the result and return a 200 or 40x depending on the result. Do note that waiting is not always a good thing. When possible, use Servlet 3 async to send the response, as it prevents you from blocking a HTTP thread.

Third option, which could be a little more complex, is to subscribe to the Event Bus for the result of an action. When the result is detected, you return the same way as you would have done using the callback method described earlier (either immediate 302 with request for result, or wait and send a 200/40x).

If you’re planning to use the send-and-wait method, you may want to consider using the CommandGateway concept, as it allows you to easily configure if and how long you want to wait. (See http://www.axonframework.org/docs/2.0/command-handling.html#d4e221).

In the end, it’s all about deciding what the semantics of the rest api are. Does 200 mean “thanks for the message, we’ve got it in order”, or does it mean “thanks, we’ve processed your request, and it’s ok”. The first is faster, the second more reliable.

Hope that helps.
Cheers,

Allard

Hi Allard, great explanation, this was supremely helpful. So. It looks like I need to make a decision about Simple vs say the Disruptor Bus early as it impacts the error handling arch. And yeah, I’m actually using Axon with Scala/Play so Async HTTP is pretty easy.

Hi Allard,
I am also working on a similar stack (Play with Axon). I am looking for some options about how to handle errors at the Event handling level. One way is use a ErrorHandler and have a retry policy as per the need basis. I am wondering if this is OK that after the retry exhaustion, i should do some kind of logging (similar Dead letter queue) and move forward. This will definitely get my View to be in a inconsistent state but I guess that will be corrected eventually. This approach looks fine, but just wondering if there is something better that can be done?

Hi Gaurav,

if you use a replay strategy, you could wrap that strategy in one that logs the event to a special location when the strategy has decided to not retry a certain event (any more). Of course, you’d have to monitor that log and act upon them manually.

Cheers,

Allard