I have a case of timing in my CQRS/ES design. For the sake of discussion let's base it on Microsoft's example on this topic, conference management (https://msdn.microsoft.com/en-us/library/jj554200.aspx).
Two contexts: conference management and order management. In conference management you create conference and change its properties (e.g.: maximum seats). Conference management communicates with order management through event bus. This way order management knows when a new conference is created, and instantiate a tracking object (seat availability) within its context. Event like "max seat availability is reduced from 100 to 80" is also communicated from conf mgmt to order mgmt through event bus.
- Let's say at minute 1 conference is created (maximum seats 20).
- At minute 4 the event arrives at order mgmt context, and hence a seat availibility is created.
- At minute 7 user made an order (through order management), buying the entire 20 seats. (this should be communicated as well from - order management to conf management so that conf admin can make proper decision).
- At minute 8 conf admin made change to seats availability (in the conf mgmt context), reducing it to 15.
- The notification from order mgmt (about the fact that all the 20 seats have been sold) arrives at minute 9.
- What to do now? (at the conf mgmt? you weren't supposed to reduced the seats to 15 when you already have received payment for 20; but at minute 8 the admin didn't know about it).
That's the first case.
Now the second case:
- Let's say at minute 1 conference is created (maximum seats 20).
- At minute 4 the event arrives at order mgmt context, and hence a seat availibility is created.
- At minute 6 conf admin made change to seats availability (in the conf mgmt context), reducing it to 15.
- At minute 7 user made an order (through order management), buying the entire 20 seats. He doesn't know that the availability has been reduced to 15 because the event hasn't arrived at this point.
- At minute 10 the notification from conf mgmt finally arrived.
- What to do now?
These problems stem from technical issues (latency in event transmission). Is there a purely technical ways to avoid it? If not, what would be the business-way / design-way to overcome it?
Added note: I'm aware this is the eventual-consistency problem pertinent to CQRS/ES architecture. Within a single context, this might be easier to tackle, because you can have commands (e.g.: undo) for that. But, between bounded contexts you shouldn't pass on commands, you only communicates with events, and I think event is not the right abstraction for this (because it represents something that happened). Or am I missing something?
Added note: maybe this article can provide more context and hint to solution, though for this specific case in this question I don't think so (it's not about out-of-order message). http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/
Added note: or maybe..., in the order management context, we can simply queue the command for buying a seat, until we know that we have received the latest / last event from the conference management context. I mean, the events come with a timestamp, right? So we can compare the timestamp of the last event we received from conf mgmt context with the timestamp of the command for seat purchase. If the ts of last event is less than the ts of the command, we simply hold off the execution of the command, until we receive an event whose ts is bigger than ts of the command. That kind of thing would be the responsibility of the process manager (saga).
Would that work? Is it the correct approach?
Added note: relevant thread > Implementing a Saga/Process Manager in a CQRS http application . I think we're on the right track with process manager. As the answerer said: "You simply don't answer "Order Confirmed" immediately. Take a look at how Amazon and other shopping sites do it: Upon Order submission, you just receive an "Order Accepted confirmation (e.g., HTTP Code 202 Accepted).".
It's up to your process-manager's logic to decide when to actually execute the command (based on certain condition, internal state maybe, or in this case the latest received event from the other context).
Any opinions?
Thanks, Raka