wonderful world
wonderful world

Reputation: 11599

NServiceBus and concurrency

This link talks about how NServiceBus handle concurrency for sagas. However, it does not show an example that explains when the concurrency can happen. In an e-commerce application, the orders are per user so there is not a case of multiple users updating the same order. I don't see a case of an Order System and Shipping System updating the same order (an Order saga). They happen at different times.

Does the question of concurrency issue raise unless a developer writes code to update the same order by multiple agents at the same time?

Upvotes: 2

Views: 1580

Answers (2)

Ramon Smits
Ramon Smits

Reputation: 2618

Concurrency example with possible dirty write

A simple concurrency example would be when you have order items. Each item is added by a separate message.

They share the same order ID. Assume that these message get processes in parallel, now a concurrency issue can occur as both want to extend the order saga so one of these must fail and retry or else we will have a dirty write.

Infinite threads/workers

Another way of seeing if there could be potentially concurrency issues is imagining having infinite threads that are able to process your complete backlog of messages and think if this could result in multiple messages wanting to either create, update or delete a saga instance and if that could cause issues.

Idempotency and more than once delivery

Concurrency issues can also occur when the same message received multiple times. This requires deduplication or other forms of idempotent processing. Not all queue transports offer 'only once delivery' as a lot of them are not transactional or are configured for high availability.

Event ordering

It is a good assumption to always expect events to arrive out or order even when events are chronological by nature as you are not in control of when other endpoints will be able to process messages.

You can only rely on that if the saga instance is in control of a specific piece of workflow.

Upvotes: 3

Yannick Meeus
Yannick Meeus

Reputation: 5890

The key to understanding what kind of scenario concurrency checks are relevant for:

If your endpoint runs with more than one worker thread, it is possible that multiple messages will hit the same saga instance simultaneously.

Let's say you have multiple threads dealing with the same incoming message, which isn't a rarity in a system that's designed to be highly performant. For the sake of argument, let's say we have an event called "OrderAccepted", which is the trigger for an order to be taken from creation to fulfillment.

If you have more than one thread handling that event, and a corresponding saga which should take this order from start to finish, you only want one thread to actually wire up said saga and start the processing. Otherwise you'd get in a situation where potentially you'll be allocating stock twice, taking payment twice, ...

So to answer your question: Different processes are of course allowed to act on different messages, one process can instantiate a saga to create the order, another process can instantiate a saga to flag an order for shipping when handling a different message, etc.

The problem that the saga concurrency checks are trying to solve are race conditions where both (or even more) processes are trying to act on a message in the same way, which could lead to duplicate actions being taken.

To illustrate how they do this, let's give a saga a revision (or version) number.

  1. A message is put on the bus, called "CreateOrder" with an orderID of "1"
  2. Process A and B both try to process the message
  3. Process A instantiates a new saga, which is given a revision of 1
  4. Process B instantiates a new saga at virtually the same time, which is also given a revision of 1
  5. Process A's saga processes the message and the saga is commited with revision 1 6/ Process B's saga processes the message, tries to commit, notices it's revision does not match as revision 1 has already been commited. It then rolls back it's actions. First level retries (and potentially second level retries) kick in.
  6. Process B tries to handle message again as part of the retries, the existing saga is loaded up, the idem-potency checks kick in and Process B notices that the message has already been handled and does nothing.

Upvotes: 1

Related Questions