Say I have a Saga that does money transfer in a few milliseconds. I have REST controller which invokes the command that triggers the Saga. How can I wait for the end of the Saga to check the results or exception to have my controller return as a response? If it were simply a lone command that doesn't trigger a Saga, I could use a command gateway and a callback that will notify me of success or failure.
UPDATE:
I was able to have my controller return a response after Saga ends by:
1) My controller method returns a DeferredResult which I save into a map
2) My controller has an event handler which listens for an end event, retrieves the DeferredResult from the map, and sets the result
Is there a better way to go about this?
Axon is designed to decouple different components. Some components handle commands and produce events, other consume events and update a query model, or in the case of a Saga, produce commands again.
Preferably, user interfaces should be designed to also work in this 'eventually consistent' way. When sending a command, the return value just indicates that the command was handled successfully, not that all the side-effects have been executed.
The reason is simple when using an exaggerated example: what if 100 components are interested in an Event produced as a result of a command. Do you want your command handler to block until all these 100 components have been updated? That would cause dramatic (technical) coupling between these components with a huge impact on scalability.
Given that background, you probably still want to update a UI based on changes in read models. If yo expect a certain side-effect to happen any time soon, using DeferredResult or CompletableFuture is a very elegant way to go about. It's basically a style of query where you say: 'let me know when ...', as opposed to 'give me your current state'. Alternatively, you can also push updates to consumers in real-time. We have implemented this in several projects based on Stomp (with Spring Websockets).
Don't forget to eventually clean deferred results from your map in case they have timed out (see DeferredResult.onTimeout()
. It would be a pity if your machine crashed because of excessive memory consumption.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With