Background:
- we have 2 bounded context: Inventory and Sale
- application context is Point-of-sale system
Scenario:
When a Checkout happen on Sale BC, we would like to decrease quantity in Inventory.
Problem:
We have 2 handlers in this problem that is interested in Checkout
or PurchaseCreated
event:
- The handler from Inventory that will decrease quantity of a Product
- The handler for a Projection that creates denormalized view.
In a synchronous environment like PHP, I can just the right order of the Event listeners.
I would like to know how this is handled in an asynchronous environment?
I would appreciate if the answer is not technology specific because then at least many of us will benefit from the answer.
Why:
The Checkout event only contains (in simplest form):
- Date of transaction
- Product infos (id, name, quantity bought, and current price).
The projection for reporting shows what products are bought and quantity left and total sale.
The order of Event handler is important for the Projection to be accurate. The denormalized view contains data not in the Checkout event which is the "stock quantity".
If the Projection queries the Inventory first, it can subtract the stock quantity to the quantity bought
BUT
If the Inventory handler comes first, it would be inaccurate if stock quantity would be subtracted from quantity bought.
Solution:
Just like VoiceOfUnreason said:
In distributed environments, you are more likely to see an "eventually consistent" approach taken...
The solution in our example based on the quote now is to just query the Inventory for its stock quantity AND listen to ProductTaken event from Inventory BC.
If Inventory handler comes first and then the Projection, then the Stock quantity left is now updated.
If Projection comes first and then the Inventory handler, it will still going to be accurate... eventually. We can listen to ProductTaken and just update accordingly.
The problem in the OP was the Projection tries to subtract quantity bought from Inventory when it should be our source of truth and dont need to do a math operation on them.
Shop -> OrderPlaced -> Payment -> PaymentReceived -> Inventory -> ProductsTaken -> Shipping -> ProductsShipped
. This (roughly) has been an industry standard for 30 years. Notice that there is no branching! Linear system flows are easy to understand/maintain.