Reputation: 16599
I have started implementing microservices in an Event-Driven Architecture. Therefore some of my services are publishing events and listening to some other events. It is very straightforward to implement a listener when an action depends on one single event, for example;
ORDER SERVICE
1. Publishes `ORDER_INTENT_EVENT` then
2. Listens for `CREDIT_AVAILABLE_EVENT` then
3. Finishes the `Order`
CREDIT SERVICE
1. Listens for `ORDER_INTENT_EVENT` then
2. Verifies if the client has credit then locks the amount and
3. Publishes `CREDIT_AVAILABLE_EVENT`
The problem arises when OrderService has to wait for more than one event, for example;
ORDER SERVICE
1. Publishes `ORDER_INTENT_EVENT` then
2. Listens for `CREDIT_AVAILABLE_EVENT`
and `INVENTORY_AVAILABLE_EVENT` then <--- Problem here
3. Finishes the `Order`
CREDIT SERVICE
1. Listens for `ORDER_INTENT_EVENT` then
2. Verifies if the client has credit then locks the amount and
3. Publishes `CREDIT_AVAILABLE_EVENT`
INVENTORY SERVICE
1. Listens for `ORDER_INTENT_EVENT` then
2. Verifies if inventory has items then locks the items and
3. Publishes `INVENTORY_AVAILABLE_EVENT`
The thing is; I am pooling both queues CREDIT_AVAILABLE_QUEUE
and INVENTORY_AVAILABLE_QUEUE
,
and both events has to be present so I can finish an order. How can I coordinate so that OrderService sees both events as only one?
I can implement it at the application level, for example; if one event arises I save it to the database and check if there is the other corresponding event to same order, if so I proceed with finishing the order, if not I do nothing then when the other event arrives I will have both of them so I am able to finish the order. The problem with this approach is that there is a minimal chance of receiving both events at the same time generating race conditions.
What is the suggested pattern for this kind of scenario?
PS.: I found this similar question but one answer suggests .net related tools and the other points to a third party service. I am interested in a pattern/code solution.
Upvotes: 3
Views: 1338
Reputation: 9473
Any time you have multiple input sources to a particular piece of state, you have the potential for a race condition. This is why we have locks. You MUST use a lock of some sort to handle the race condition.
This may be implemented at the database layer, or using a locking library, or a shared piece of memory (please use a locking library unless you have way more understanding of memory / CPU architecture than this posting implies).
Most languages implement some form of mutex locking to allow this problem to be solved. If you are using multiple processes / machines / etc, you will need some form of external mutex locking (often implemented by your database provider). If you lack this, there are distributed lock systems that also can be used.
Upvotes: 0