How to Architect Asynchronous Microservices?
Firstly, Let's see a story of how Alice can order pizza online, while she worked in her office and when the pizza was ready, she gets a notification for pickup!
Technically, in the above scenario, Alice placed an order via the web or mobile for a "Pizza" and immediately saw a response that her order was accepted. The request to the server was immediately responded to with a 200(OK) response.
That's exactly, the true meaning of being asynchronous, you don't have to wait for the whole process to be complete in order to respond to the request from a user. Non-Blocking isn't it !!!
In terms of UI/UX this is super important as it ties back to one of the important touch points>> Smooth and Easy User Experience !!!
When do you need to implement Asynchronous communications?
If you ever find yourself in situations where you wanted to tell an event of some kind has happened and wanted a set of tasks to be executed upon that event or you wanted to initiate a long-running job, you'd be able to consider these for async communications.
Now that I told you what asynchronous communications mean, how is it implemented in reality, to real-world software components that operate on this principle?
There are two ways to implement
Event
API
Scenarios:
GIVEN Alice has access a mobile or a laptop to place a pizza order
WHEN she places the order for the pizza
THEN OrderPlaced Event is triggered by the OrderService(Sender).
GIVEN the order was placed
WHEN the OrderPlaced event got fired
THEN OrderHistoryService(Consumer) updates the order history of the user. Order Progress updates are triggered as OrderStatus Events to the User during the Pizza Baking journey.
If you see the above scenarios we feel that we need to have a Message Broker to help us capture the events and store them so that whenever the OrderHistory Service is ready it can consume the order placed message and update the Order History of the user. Even further, OrderPlaced event can can be even used by OrderExecutor Service which walks the pizza journey Prep, Bake, Oven stages and trigger OrderStatus events during each stage.
So we see ourselves that the Order Placed event may be useful by more than one Service technically.
This leads us to the discussion of common design patterns
Queuing - Competing Workers Pattern
Fanout Pattern
The message broker could be RabbitMQ or any other messaging service.
Direct Exchange:
The Order placed event is stored by the RabbitMQ message broker and the several workers of Order Service compete to get that event. This helps the to evenly spread the load when there is a surge in the user requests flowing to the systems.
Fan out Exchange:
Useful when the same event is needed by more than one service to perform its intended business functions.
Async API Calls:
The Client here could be a web application, it calls the API, the API receives the request and processes the request in the background and immediately return the response, without blocking the client application. When the process is completed the result is delivered to the callback address that initially came with the API request.
This is a variation of the request/response pattern where the response is not blocked by the task execution.