My understanding is that AxonServer must be contacted first in any case, even if the command routing algorithm selects the JVM, which dispatched the command originally. I believe this is the source code responsible for that part.
I indeed agree with you but was making a guesstimate based on what I pulled from your description. I now notice that was a wrong assumption from my part, based on the following line in your original message:
Method returns without complaints when AxonServer is not running.
This to me sounds like everything worked fine, but I believe what you intended to share is that the CompletableFuture
returned, albeit with an exceptional result.
Back to the actual thing you are investigating, sendAndWait()
will bubble up the exception, as you have likely noticed. Internally sendAndWait()
is nothing more than the send()
operation, where the framework waits for the outcome of the CompletableFuture
for you.
This indeed makes your assumption correct. Not checking the outcome of the CompletableFuture
will simply not land you the CommandDispatchException
directly in your face. You will instead have to check when the future is complete yourself if this is required. Or let another component, like Spring’s Web UI, resolve it for you.
I’d wager the definition of “received” in the documentation is what put you off in this case. I would say you did provide the command to the CommandBus
inside your JVM by any means. Whether it went from one end to another, so if dispatching succeeded, is still up for debate.
Maybe we should turn this situation around, by going back to your original statement:
But I’d like to respond to clients with an error if the command wasn’t ACKed by bus.
Followed up by your first question:
Is there any way to distinguish command dispatching failures from command handling failures?
I would assume that either, regardless of whether you use send
or sendAndWait
on the CommandGateway
, or dispatch(C)
/ dispatch(C, CommandCallback<C, R>)
on the CommandBus
, can be achieved by checking for the aforementioned exceptions in my previous response. The checking approach is just different:
CommandGateway#send(Object)
- The exception from the CompletableFuture
will be rethrown from, so you can add a try-catch if needed.
CommandGateway#sendAndWait(Object)
- The outcome is present in the CompletableFuture
, which should be validated in your set up
CommandBus#dispatch(C)
- This would net you, sadly, nothing, as the CommandCallback
used in this case is a no-op
CommandBus#dispatch(C, CommandCallback<C, R>)
- The result is returned to the CommandCallback#onResult
, where the CommandResultMessage
should be validated.
By the way, if you feel the description is too ambiguous right now, any improvements are always fair game as pull requests of course. Furthermore, I hope this clarifies your option further @Beka_Tsotsoria. If anything else is still open, definitely reach out.