I am implementing an order management system for a restaurant using Axon.
Scenario:
Users can add or remove menu items from an order. At some point, there is an order summary page that provides an overview of the selected products and the total order price, which is calculated in the backend.
The customer must then confirm their selection to finally send the order to the restaurant.
The order summary page is powered by a projection (e.g., OrderSummaryView), which consumes multiple events like ItemAdded, ItemQuantityIncreased, etc.
Question:
How can we ensure that the OrderSummaryView contains all the relevant events, meaning all selected products, quantities, and the correct total price?
What strategies can be applied in event-sourced systems, and what does Axon offer out of the box to handle this?
I encountered a similar situation. The approach I took is using the version (=sequence number) number of the aggregate to check if the record in the read model is updated.
To handle the case when multiple projections need to be updated based on one event Iâam also checking if all streaming event processor have the same TrackingToken index. This indicates that they are done processing and therefore the read model must be updated.
I implemented a spring component to verify this which basically is used as a predicate which you can pass to functions who need to be aware of this status.
I assume there might be better approaches, but we use the âtemporary solutionâ for quite sometime now without issuesâŚ
the question seems to be quite broad, but your introduction makes me assume you mean that youâd want to ensure that when an order as seen by the user in the Order Summary Page hasnât been changed in the meantime when they confirm it?
The easiest way to achieve that in Axon, is to store the SequenceNumber of an event in the projection. This is essentially the âversionâ of your order. Each event will contain this sequence.
When you send a ConfirmOrder, you can pass this sequence number as the expected aggregate version. If ou use the (default) annotated approach, besides @TargetAggregateIdentifier, you can annotate the field carrying this sequence number with @TargetAggregateVersion.
By default, this will reject any commands if the aggregate has applied events since that last sequence.
Additionally, you can add a parameter of type ConflictResolver to your command handler and define which âunseenâ changes are considered conflicts and which are not.
You can find more about conflict detection in the reference guide: Conflict Resolution
I hope I interpreted your question correctly and that this provided some guidance.