How to ensure consistency when you need it

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?

1 Like

Hi Matthias,

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…

1 Like

Hi Matthias,

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.

3 Likes