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