A business transaction can be many times more complex than a normal database transaction.
Imagine you are placing an order on an e-commerce platform like Amazon. From the moment you click the "Buy" button to the point where you accept the delivery at your doorstep, a series of steps takes place, forming a complete business transaction.
Here are some steps that might happen:
Placing an Order: The user selects the desired products, adds them to the cart, and initiates the checkout process. This step involves capturing the order details, such as the items, quantities, and shipping address.
Creating an Invoice: Once the order is placed, an invoice is generated. The invoice serves as a record of the transaction and is used for billing and accounting purposes.
Handling Payments: The payment process is initiated, where the user provides their payment information, such as credit card details. The payment is processed securely, and upon successful completion, the order is confirmed.
Shipping the Product: After the payment is processed, the order is prepared for shipping. Tracking information is generated, and the user is notified of the estimated delivery date.
Each of these steps involves interactions with different microservices, such as the order service, payment service, and shipping service.
The challenge lies in coordinating these microservices to ensure that the entire business transaction is executed successfully and consistently.
The Saga Pattern to the Rescue
Fortunately, the Saga pattern can save the day.
The Saga pattern is a design approach that breaks down a complex business transaction into a series of smaller, independent steps, each handled by a separate microservice.
There are two main ways you can implement a Saga:
Orchestration-Based Saga
In an Orchestration-Based Saga, the orchestrator acts as the conductor of an orchestra, directing and coordinating the various steps involved in the saga.
The orchestrator explicitly defines the Saga's workflow, specifying the sequence of steps and the dependencies between them. This centralized approach makes it easier to visualize and reason about the overall process, as the logic is encapsulated within the orchestrator.
Let's consider an example of an order processing system. As we saw, the order processing involves multiple steps, such as:
Placing the order
Validating the order
Processing the payment
Updating the inventory
Shipping the order
The orchestrator would first trigger the placing of the order.
Once the order is placed, it will validate the order details. If the validation succeeds, the orchestrator will initiate the payment processing step.
After the payment is successfully processed, the orchestrator will update the inventory to reflect the sold items.
Finally, it would trigger the shipping process to deliver the order to the customer.
If any step in the saga fails, the orchestrator would handle the failure and initiate compensating actions to roll back the previous steps and maintain data consistency.
Orchestration-Based Saga is particularly effective in the following scenarios:
When dealing with complex business processes that involve multiple steps and decision points
When the workflow is well-defined and follows a predetermined sequence of steps.
When there are strict dependencies between the steps of the Saga.
Choreography-Based Saga
In a Choreography-Based Saga, each service involved in the Saga communicates directly with others by publishing events. Instead of relying on a central orchestrator to coordinate the steps, the services themselves are responsible for making decisions and reacting to events.
When a service performs an action or encounters a notable condition within its domain, it publishes an event to notify other services. The event contains relevant information about the action or condition, allowing other services to react accordingly.
When a service receives an event, it evaluates the event based on its own business rules and determines the appropriate course of action.
Let’s understand it better using our order processing example.
The Order Service receives a new order request and creates an order. It publishes an "OrderCreated" event.
The Payment Service listens for the "OrderCreated" event and initiates the payment processing. If the payment is successful, it publishes a "PaymentSucceeded" event. If the payment fails, it publishes a "PaymentFailed" event.
The Inventory Service listens for the "PaymentSucceeded" event and checks the availability of the ordered items. If the items are available, it reserves them and publishes an "InventoryReserved" event. If the items are out of stock, it publishes an "InventoryUnavailable" event.
The Shipping Service listens for the "InventoryReserved" event and arranges for the shipping of the order. It publishes a "ShippingArranged" event.
If any service encounters an error or receives a compensating event (e.g., "PaymentFailed" or "InventoryUnavailable"), it performs the necessary compensating actions. For example, if the Payment Service receives a "PaymentFailed" event, it cancels the order and publishes an "OrderCancelled" event.
Choreography-Based Saga is particularly well-suited for the following scenarios:
Situations where the workflow is dynamic and can change over time.
It encourages loose coupling between services, allowing each service to evolve at its own pace.
So - have you used the Saga approach?
Shoutout
Here are some interesting articles I’ve read recently:
Distributed Services can't exist without Eventual Consistency by Raul Junco
How to write the CV you're proud of by
System Design: What is Availability? by
That’s it for today! ☀️
Enjoyed this issue of the newsletter?
Share with your friends and colleagues.
See you later with another edition — Saurabh
I love this pattern, it solves the problem efficiently, awesome newsletter post my friend!
Orchestration based Saga looks very similar to 2-phase-commit. It would be great if you compare both of them in your future newsletter. Thanks Saurabh!!!