Showing posts with label Saga Design Pattern – Complete Guide with E-Commerce Example. Show all posts
Showing posts with label Saga Design Pattern – Complete Guide with E-Commerce Example. Show all posts

Thursday, August 20, 2026

Saga Design Pattern – Complete Guide with E-Commerce Example

1. What Problem Does Saga Solve?

Imagine an e-commerce application with these microservices:

                    E-Commerce Application
                            |
        +-------------------+-------------------+
        |                   |                   |
   Order Service       Payment Service     Inventory Service
        |                   |                   |
        +-------------------+-------------------+
                            |
                    Shipping Service

A customer places an order.

The business process might be:

Create Order
    ↓
Reserve Inventory
    ↓
Process Payment
    ↓
Create Shipment
    ↓
Order Completed

The problem is that each operation belongs to a different database.

For example:

Order Service       → OrderDB
Inventory Service   → InventoryDB
Payment Service     → PaymentDB
Shipping Service    → ShippingDB

We cannot normally use a single SQL transaction such as:

BEGIN TRANSACTION

OrderDB
InventoryDB
PaymentDB
ShippingDB

COMMIT

because these are independent microservices.

This is where Saga Pattern comes in.


2. What Is Saga Design Pattern?

A Saga is a sequence of local transactions where each microservice performs its own transaction.

If one transaction fails, previously completed transactions are compensated by executing corresponding compensating transactions.

Conceptually:

Transaction 1
     ↓
Transaction 2
     ↓
Transaction 3
     ↓
Transaction 4

If Transaction 3 fails:

Transaction 1 ✓
Transaction 2 ✓
Transaction 3 ✗

        ↓

Compensation 2
        ↓
Compensation 1

So instead of a traditional distributed ACID transaction, Saga provides eventual consistency using local transactions + compensation.


3. E-Commerce Example

Suppose customer places an order:

Order #1001

Product: Laptop
Quantity: 1
Price: ₹80,000

The workflow is:

Customer
   |
   ↓
Order Service
   |
   ↓
Inventory Service
   |
   ↓
Payment Service
   |
   ↓
Shipping Service
   |
   ↓
Order Completed

Let's define the transactions.

T1 – Create Order

Order Service:

Order Status = Pending

T2 – Reserve Inventory

Inventory Service:

Laptop Stock
100 → 99

T3 – Process Payment

Payment Service:

₹80,000 charged

T4 – Create Shipment

Shipping Service:

Shipment Created

Finally:

Order Status = Confirmed

4. What Happens If Payment Fails?

Suppose:

T1 Create Order        ✓
T2 Reserve Inventory   ✓
T3 Payment             ✗

We cannot simply rollback T1 and T2 using a normal database rollback because they happened in different databases.

Instead:

Payment Failed
      ↓
Release Inventory
      ↓
Cancel Order

So:

T1 Create Order ✓
       ↓
T2 Reserve Stock ✓
       ↓
T3 Payment ✗
       ↓
C2 Release Stock ✓
       ↓
C1 Cancel Order ✓

This is the core concept of Saga.


5. Saga Has Two Main Approaches

There are two major implementations.

Approach 1 – Choreography

Services communicate through events.

Order Service
     |
 OrderCreated
     ↓
Inventory Service
     |
InventoryReserved
     ↓
Payment Service
     |
PaymentCompleted
     ↓
Shipping Service

There is no central coordinator.


Approach 2 – Orchestration

A central Saga Orchestrator controls the workflow.

                 Saga Orchestrator
                        |
          +-------------+-------------+
          |             |             |
          ↓             ↓             ↓
      Order          Inventory      Payment
      Service         Service       Service
                                      |
                                      ↓
                                  Shipping

The orchestrator says:

Reserve inventory

then:

Process payment

then:

Create shipment

If something fails:

Release inventory
Cancel order

For an enterprise e-commerce application, orchestration is often easier to understand and manage, especially when the workflow becomes complex.


6. Which One Should We Use?

FeatureChoreographyOrchestration
Central controllerNoYes
Simple workflowsExcellentGood
Complex workflowsDifficultExcellent
DebuggingDifficultEasier
Business workflow visibilityLowerHigher
CouplingEvent-basedOrchestrator-based
Failure handlingDistributedCentralized
Large enterprise workflowsCan become complicatedOften preferable

For the example below, I'll use Saga Orchestration.


7. Overall Architecture

Let's design the system.

                         Client
                           |
                           ↓
                    API Gateway
                           |
                           ↓
                    Order Service
                           |
                           ↓
                  Saga Orchestrator
                           |
          +----------------+----------------+
          |                |                |
          ↓                ↓                ↓
     Inventory          Payment          Shipping
      Service           Service           Service
          |                |                |
      InventoryDB       PaymentDB       ShippingDB

Communication could use:

Azure Service Bus
Kafka
RabbitMQ

For an Azure-based .NET system, Azure Service Bus is a natural choice.


8. Database Design

An important Saga principle is:

Each microservice owns its own database.

Don't do this:

Order Service
       |
       ↓
Shared Database
       ↑
       |
Inventory Service

Instead:

Order Service
     ↓
OrderDB

Inventory Service
     ↓
InventoryDB

Payment Service
     ↓
PaymentDB

Shipping Service
     ↓
ShippingDB

9. Order Model

Order Service might have:

public class Order
{
    public Guid Id { get; set; }

    public Guid CustomerId { get; set; }

    public decimal TotalAmount { get; set; }

    public OrderStatus Status { get; set; }

    public DateTime CreatedAt { get; set; }
}

Status:

public enum OrderStatus
{
    Pending,
    InventoryReserved,
    PaymentProcessing,
    Confirmed,
    Failed,
    Cancelled
}

10. Order Items

public class OrderItem
{
    public Guid Id { get; set; }

    public Guid OrderId { get; set; }

    public Guid ProductId { get; set; }

    public int Quantity { get; set; }

    public decimal Price { get; set; }
}

11. Inventory Model

Inventory Service owns:

public class Inventory
{
    public Guid ProductId { get; set; }

    public int AvailableQuantity { get; set; }

    public int ReservedQuantity { get; set; }
}

Example:

Product       Available     Reserved

Laptop          100            0

After reservation:

Laptop           99            1

12. Inventory Reservation Model

We should maintain a separate reservation record.

public class InventoryReservation
{
    public Guid Id { get; set; }

    public Guid OrderId { get; set; }

    public Guid ProductId { get; set; }

    public int Quantity { get; set; }

    public ReservationStatus Status { get; set; }
}

Status:

public enum ReservationStatus
{
    Reserved,
    Released
}

Why?

Because Saga requires us to know:

What exactly should I compensate?


13. Payment Model

Payment Service:

public class Payment
{
    public Guid Id { get; set; }

    public Guid OrderId { get; set; }

    public decimal Amount { get; set; }

    public PaymentStatus Status { get; set; }

    public string TransactionReference { get; set; }
}

Status:

public enum PaymentStatus
{
    Pending,
    Completed,
    Failed,
    Refunded
}

14. Shipment Model

Shipping Service:

public class Shipment
{
    public Guid Id { get; set; }

    public Guid OrderId { get; set; }

    public string Address { get; set; }

    public ShipmentStatus Status { get; set; }
}

15. Saga State Model

The orchestrator should maintain Saga state.

For example:

public class OrderSaga
{
    public Guid SagaId { get; set; }

    public Guid OrderId { get; set; }

    public SagaStatus Status { get; set; }

    public bool OrderCreated { get; set; }

    public bool InventoryReserved { get; set; }

    public bool PaymentCompleted { get; set; }

    public bool ShipmentCreated { get; set; }

    public DateTime CreatedAt { get; set; }

    public DateTime UpdatedAt { get; set; }
}

This becomes very useful for:

  • monitoring

  • retries

  • recovery

  • debugging

  • compensation


16. Complete Saga Flow

Let's look at the complete process.

Customer
   |
   | Place Order
   ↓
Order Service
   |
   | Order Created
   ↓
Saga Orchestrator
   |
   | Reserve Inventory
   ↓
Inventory Service
   |
   | Inventory Reserved
   ↓
Saga Orchestrator
   |
   | Process Payment
   ↓
Payment Service
   |
   | Payment Completed
   ↓
Saga Orchestrator
   |
   | Create Shipment
   ↓
Shipping Service
   |
   | Shipment Created
   ↓
Saga Orchestrator
   |
   ↓
Order Confirmed

17. Step 1 – Customer Creates Order

Client:

POST /api/orders

Request:

{
  "customerId": "C001",
  "items": [
    {
      "productId": "P100",
      "quantity": 1
    }
  ]
}

Order Service creates:

OrderId = 1001
Status = Pending

Database:

Orders

1001 | C001 | 80000 | Pending

Then publish:

OrderCreated

Event:

public record OrderCreatedEvent(
    Guid OrderId,
    Guid CustomerId,
    decimal Amount);

18. Step 2 – Saga Starts

The orchestrator receives:

OrderCreated

It creates:

SagaId = S1001
OrderId = 1001
Status = Started

Then sends:

ReserveInventory

19. Step 3 – Inventory Reservation

Inventory Service receives:

{
  "sagaId": "S1001",
  "orderId": "1001",
  "productId": "P100",
  "quantity": 1
}

It executes a local database transaction.

For example:

BEGIN TRANSACTION

Check available stock

Available = Available - 1

Create Reservation

COMMIT

Database becomes:

Available = 99
Reserved = 1

Then publish:

InventoryReserved

20. Step 4 – Payment

Saga orchestrator receives:

InventoryReserved

Then sends:

ProcessPayment

Payment Service:

BEGIN TRANSACTION

Create Payment
Status = Processing

Call payment provider

Payment successful

Status = Completed

COMMIT

Then:

PaymentCompleted

21. Step 5 – Shipping

Saga receives:

PaymentCompleted

Then:

CreateShipment

Shipping Service creates:

ShipmentId = SH1001
OrderId = 1001
Status = Created

Then publishes:

ShipmentCreated

22. Step 6 – Complete Saga

Saga Orchestrator receives:

ShipmentCreated

Now:

OrderCreated       ✓
InventoryReserved  ✓
PaymentCompleted   ✓
ShipmentCreated    ✓

So:

Saga Status = Completed

And Order Service is instructed:

ConfirmOrder

Order:

1001 | Confirmed

23. What Happens When Payment Fails?

This is where Saga becomes interesting.

Suppose:

Order Created       ✓
Inventory Reserved  ✓
Payment             ✗

The orchestrator receives:

PaymentFailed

It knows:

InventoryReserved = true
PaymentCompleted = false

Therefore compensation is required.


24. Compensation Flow

The orchestrator sends:

ReleaseInventory

Inventory Service:

BEGIN TRANSACTION

Available = Available + 1

Reservation.Status = Released

COMMIT

Now:

Available = 100
Reserved = 0

Then orchestrator sends:

CancelOrder

Order Service:

Order.Status = Cancelled

Final state:

Order       = Cancelled
Inventory   = Released
Payment     = Failed
Saga        = Compensated

25. Important Point – Compensation Is NOT Rollback

This is one of the most important interview concepts.

Traditional transaction:

BEGIN

Operation A
Operation B
Operation C

ROLLBACK

Saga:

Operation A
Operation B
Operation C → FAILED

Compensation B
Compensation A

There is no global database rollback.

Instead:

A compensating transaction semantically reverses the business effect of a previous transaction.


26. Example: Payment Succeeds but Shipping Fails

Consider:

Order        ✓
Inventory    ✓
Payment      ✓
Shipping     ✗

Now we need to compensate.

Possible sequence:

Shipping Failed
       ↓
Refund Payment
       ↓
Release Inventory
       ↓
Cancel Order

So:

T1 Create Order       ✓
T2 Reserve Inventory  ✓
T3 Payment            ✓
T4 Shipping           ✗

C3 Refund Payment     ✓
C2 Release Inventory  ✓
C1 Cancel Order       ✓

Final:

Order = Cancelled
Inventory = Released
Payment = Refunded
Shipping = Failed

27. What If Compensation Also Fails?

This is a very important real-world scenario.

Suppose:

Payment Failed
      ↓
Release Inventory
      ↓
Inventory Service FAILED

Now:

Order = Pending
Inventory = Reserved
Payment = Failed

We cannot simply give up.

The Saga must retry the compensation.

ReleaseInventory
      ↓
FAILED
      ↓
Retry
      ↓
FAILED
      ↓
Retry
      ↓
SUCCESS

Therefore Saga implementations need:

  • Retry

  • Dead-letter queue

  • Idempotency

  • Timeout

  • Monitoring

  • Manual recovery


28. Retry Strategy

For example:

Attempt 1
   ↓
5 seconds
   ↓
Attempt 2
   ↓
30 seconds
   ↓
Attempt 3
   ↓
5 minutes

This is called exponential backoff.

For Azure Service Bus, failed messages can eventually be moved to a dead-letter queue.


29. Idempotency Is Extremely Important

Suppose:

ReserveInventory

message is delivered twice.

Without idempotency:

Message 1 → Reserve 1 item
Message 2 → Reserve another item

Incorrect:

Stock: 100 → 98

But we wanted:

Stock: 100 → 99

Therefore every command should have a unique identifier.

Example:

public class ProcessedMessage
{
    public Guid MessageId { get; set; }

    public DateTime ProcessedAt { get; set; }
}

Before processing:

Has MessageId already been processed?

If yes:

Ignore

Otherwise:

Process
Save MessageId

30. Better Idempotency Model

Instead of only MessageId, use a business operation ID.

Example:

SagaId = S1001
OrderId = 1001
Operation = ReserveInventory

Create unique constraint:

(SagaId, Operation)

Then duplicate commands cannot create duplicate reservations.


31. Transactional Outbox Pattern

There is another major problem.

Suppose Order Service does:

BEGIN TRANSACTION

Insert Order

COMMIT

Then:

Publish OrderCreated

What if the application crashes between these operations?

Database Insert ✓
Publish Event ✗

Now the order exists but Saga never receives the event.

This is where Transactional Outbox Pattern is commonly combined with Saga.


32. Outbox Table

Order Service database:

Orders
OutboxMessages

When creating the order:

BEGIN TRANSACTION

INSERT INTO Orders

INSERT INTO OutboxMessages

COMMIT

Both happen in the same local database transaction.

Example:

Orders

OrderId = 1001
Status = Pending

And:

OutboxMessages

MessageId = M1001
Type = OrderCreated
Payload = {...}
Published = false

A background publisher then reads:

Published = false

and sends the message.

After successful publishing:

Published = true

This greatly improves reliability.


33. Saga + Outbox Architecture

A robust architecture becomes:

                         Saga Orchestrator
                                |
                         Message Broker
                                |
          +---------------------+---------------------+
          |                     |                     |
          ↓                     ↓                     ↓
      Order Service        Inventory Service      Payment
          |                     |                     |
       OrderDB              InventoryDB           PaymentDB
          |                     |                     |
       Outbox                 Outbox                Outbox
          |                     |                     |
          +---------------------+---------------------+
                                |
                         Azure Service Bus

34. Commands vs Events

This distinction is important.

Command

A command tells another service:

Do something.

Examples:

CreateOrder
ReserveInventory
ProcessPayment
CreateShipment
RefundPayment
ReleaseInventory
CancelOrder

Event

An event says:

Something happened.

Examples:

OrderCreated
InventoryReserved
InventoryReservationFailed
PaymentCompleted
PaymentFailed
ShipmentCreated
ShipmentFailed

35. Example Command

public record ReserveInventoryCommand(
    Guid MessageId,
    Guid SagaId,
    Guid OrderId,
    Guid ProductId,
    int Quantity);

36. Example Event

public record InventoryReservedEvent(
    Guid MessageId,
    Guid SagaId,
    Guid OrderId);

Failure:

public record InventoryReservationFailedEvent(
    Guid MessageId,
    Guid SagaId,
    Guid OrderId,
    string Reason);

37. Saga State Machine

The orchestrator can be modeled as a state machine.

             OrderCreated
                  |
                  ↓
          InventoryPending
                  |
        +---------+---------+
        |                   |
     Success              Failure
        |                   |
        ↓                   ↓
 PaymentPending        CancelOrder
        |
   +----+----+
   |         |
Success     Failure
   |         |
   ↓         ↓
Shipping   ReleaseInventory
Pending       |
   |          ↓
Success    CancelOrder
   |
   ↓
Completed

This is a very good way to explain Saga in an interview.


38. Orchestrator Pseudocode

Conceptually:

public async Task Handle(OrderCreatedEvent message)
{
    await ReserveInventory(message);
}

When inventory succeeds:

public async Task Handle(InventoryReservedEvent message)
{
    await ProcessPayment(message);
}

Payment succeeds:

public async Task Handle(PaymentCompletedEvent message)
{
    await CreateShipment(message);
}

Shipment succeeds:

public async Task Handle(ShipmentCreatedEvent message)
{
    await ConfirmOrder(message);
}

Payment fails:

public async Task Handle(PaymentFailedEvent message)
{
    await ReleaseInventory(message);
    await CancelOrder(message);
}

39. Compensation Table

A useful way to design a Saga is to create a compensation matrix.

Forward TransactionCompensation
Create OrderCancel Order
Reserve InventoryRelease Inventory
Process PaymentRefund Payment
Create ShipmentCancel Shipment
Apply CouponRestore Coupon
Allocate Loyalty PointsReturn Loyalty Points

For every business transaction, ask:

If this succeeds and something later fails, how do I undo its business effect?

If you cannot answer that, your Saga design isn't complete.


40. Data Consistency

A common question is:

How does Saga maintain data consistency?

It does not provide immediate strong consistency across all databases like a single ACID transaction.

Instead it provides:

Eventual Consistency

For example:

Initially:

Order = Pending
Inventory = Reserved
Payment = Processing

After processing:

Order = Confirmed
Inventory = Reserved
Payment = Completed

Or if failure occurs:

Order = Cancelled
Inventory = Released
Payment = Failed

The system may temporarily have intermediate states, but eventually it reaches a valid business state.


41. Important: Don't Compensate Everything Blindly

Suppose:

Inventory reserved
Payment completed
Shipping failed

You shouldn't simply execute compensation commands without knowing the actual state.

Maintain Saga state:

InventoryReserved = true
PaymentCompleted = true
ShipmentCreated = false

Then compensation is based on completed steps.

if PaymentCompleted
    RefundPayment()

if InventoryReserved
    ReleaseInventory()

if OrderCreated
    CancelOrder()

42. Timeout Handling

Suppose Payment Service doesn't respond.

Payment Request
      ↓
Waiting...
      ↓
Waiting...
      ↓
Timeout

The orchestrator should not wait forever.

For example:

Payment timeout = 5 minutes

Then:

Payment Timeout
      ↓
Check payment status
      ↓
If unknown → retry/query provider
      ↓
If definitely failed → compensate

This is especially important with external payment gateways.


43. Why Payment Status Needs Special Care

Imagine:

Payment Service → Payment Gateway

Payment request is sent.

Gateway processes it.

But response is lost.

Your service sees:

Timeout

You must not automatically refund or retry blindly because the first payment might actually have succeeded.

You may accidentally charge the customer twice.

Instead use:

Idempotency Key

For example:

OrderId = 1001
PaymentAttempt = 1
IdempotencyKey = ORDER-1001-PAYMENT

The payment provider should treat repeated requests with the same key as the same logical operation where its API supports idempotency.


44. Handling Concurrent Orders

Suppose only one laptop remains.

Stock = 1

Two customers simultaneously order.

Customer A → Reserve
Customer B → Reserve

Inventory Service must use appropriate concurrency control.

For example:

UPDATE Inventory
SET AvailableQuantity = AvailableQuantity - 1
WHERE ProductId = @ProductId
AND AvailableQuantity >= 1;

Then check:

Rows affected = 1

Reservation succeeds.

If:

Rows affected = 0

reservation fails.

This prevents overselling.


45. Saga Failure Scenarios

Scenario 1

Order ✓
Inventory ✓
Payment ✓
Shipping ✓

Result:

Completed

Scenario 2

Order ✓
Inventory ✗

Compensation:

Cancel Order

Scenario 3

Order ✓
Inventory ✓
Payment ✗

Compensation:

Release Inventory
Cancel Order

Scenario 4

Order ✓
Inventory ✓
Payment ✓
Shipping ✗

Compensation:

Refund Payment
Release Inventory
Cancel Order

Scenario 5

Compensation fails

Solution:

Retry
 ↓
Retry
 ↓
Dead Letter Queue
 ↓
Operational Alert
 ↓
Manual Recovery

46. Azure Implementation

Since you're working with Azure/.NET, one possible architecture is:

ASP.NET Core
      |
      ↓
Order Service
      |
      ↓
Azure Service Bus
      |
      ↓
Saga Orchestrator
      |
      +----------------+
      |                |
      ↓                ↓
Inventory          Payment
Service            Service
      |                |
      ↓                ↓
 Azure SQL          Azure SQL

And:

Shipping Service
       |
       ↓
   Azure SQL

For monitoring:

Application Insights
Azure Monitor

For secrets:

Azure Key Vault

47. Azure Service Bus Structure

You might design:

Topic: ecommerce-events

Subscriptions:

order
inventory
payment
shipping
saga

Or use separate command queues:

inventory-commands
payment-commands
shipping-commands
order-commands

For orchestration, a command queue per service plus an event topic is often a clean conceptual model.


48. Message Flow

Example:

Order Service
     |
     | OrderCreated
     ↓
Service Bus
     |
     ↓
Saga Orchestrator
     |
     | ReserveInventory
     ↓
Inventory Queue
     |
     ↓
Inventory Service
     |
     | InventoryReserved
     ↓
Service Bus
     |
     ↓
Saga
     |
     | ProcessPayment
     ↓
Payment Queue

And so on.


49. Database Transactions Are Still Used

This is another important point.

Saga does not mean:

Don't use database transactions.

Each microservice should still use normal local transactions.

For example:

Inventory Service

BEGIN TRANSACTION

UPDATE Inventory

INSERT Reservation

INSERT OutboxMessage

COMMIT

This is a local ACID transaction.

Saga coordinates these local transactions.


50. The Golden Rule

Think about Saga like this:

Saga
 =
Multiple Local Transactions
 +
Messages
 +
State Machine
 +
Compensating Transactions
 +
Retry
 +
Idempotency
 +
Timeout Handling
 +
Observability

That is a much more accurate real-world definition than simply saying:

Saga is rollback for microservices.

It is not a distributed rollback mechanism.


51. Complete E-Commerce Flow

Here's the complete picture:

                         CUSTOMER
                            |
                            ↓
                       API Gateway
                            |
                            ↓
                     ORDER SERVICE
                            |
                       Create Order
                            |
                            ↓
                      OrderCreated
                            |
                            ↓
                   SAGA ORCHESTRATOR
                            |
                    Reserve Inventory
                            |
                            ↓
                   INVENTORY SERVICE
                            |
                   Inventory Reserved
                            |
                            ↓
                   SAGA ORCHESTRATOR
                            |
                     Process Payment
                            |
                            ↓
                    PAYMENT SERVICE
                            |
                     Payment Success
                            |
                            ↓
                   SAGA ORCHESTRATOR
                            |
                     Create Shipment
                            |
                            ↓
                   SHIPPING SERVICE
                            |
                    Shipment Created
                            |
                            ↓
                   SAGA ORCHESTRATOR
                            |
                            ↓
                     Confirm Order

Failure:

Payment Failed
      |
      ↓
Saga Orchestrator
      |
      +------→ Release Inventory
      |
      +------→ Cancel Order
      |
      ↓
Saga Compensated

52. Production-Grade Saga Checklist

When implementing Saga in a real application, consider all of these:

  • Saga ID

  • Correlation ID

  • Message ID

  • Idempotency

  • Saga state persistence

  • Local database transactions

  • Transactional Outbox

  • Reliable messaging

  • Retries

  • Exponential backoff

  • Timeouts

  • Dead-letter queues

  • Compensating transactions

  • Concurrency control

  • Optimistic/pessimistic locking where appropriate

  • Observability

  • Distributed tracing

  • Audit logging

  • Manual recovery

  • Poison message handling


53. Saga vs Two-Phase Commit

A common interview question is:

2PC

Coordinator
    |
    +--- DB1
    +--- DB2
    +--- DB3

Prepare
Prepare
Prepare

Commit
Commit
Commit

It attempts to provide distributed transactional atomicity, but can introduce blocking, coordination overhead, and operational complexity.

Saga:

Local Transaction
      ↓
Message
      ↓
Local Transaction
      ↓
Message

Failure:

Compensating Transaction

Saga is generally better suited to independently deployable microservices where business operations can be compensated.


54. Interview Answer

If an interviewer asks:

"Explain Saga Design Pattern with an e-commerce example."

A strong answer would be:

"Saga is a distributed transaction pattern used in microservices where a business transaction is divided into a sequence of local transactions. Each service commits its own transaction independently. If a later transaction fails, the Saga executes compensating transactions for the previously completed operations.

For example, in an e-commerce system, placing an order may involve creating the order, reserving inventory, processing payment, and creating a shipment. If payment fails after inventory has been reserved, the Saga doesn't perform a database rollback across services. Instead, it executes a compensating transaction to release the inventory and then cancels the order.

Saga can be implemented using choreography, where services communicate through events, or orchestration, where a central Saga orchestrator manages the workflow. In a production system, I would also use an outbox pattern, idempotent message processing, retries, timeouts, dead-letter queues, correlation IDs, and persistent Saga state to achieve reliable eventual consistency."


55. Recommended .NET Architecture

For a production .NET implementation, I would structure it approximately like this:

src
│
├── OrderService
│   ├── Controllers
│   ├── Domain
│   ├── Application
│   ├── Infrastructure
│   └── Messaging
│
├── InventoryService
│   ├── Domain
│   ├── Application
│   ├── Infrastructure
│   └── Messaging
│
├── PaymentService
│   ├── Domain
│   ├── Application
│   ├── Infrastructure
│   └── Messaging
│
├── ShippingService
│   ├── Domain
│   ├── Application
│   ├── Infrastructure
│   └── Messaging
│
└── OrderSaga
    ├── StateMachine
    ├── Commands
    ├── Events
    ├── Consumers
    └── Persistence

A particularly robust combination is:

Microservices
     +
Saga Orchestration
     +
Azure Service Bus
     +
Transactional Outbox
     +
Idempotent Consumers
     +
Retry/Timeout
     +
Dead Letter Queue
     +
Azure SQL
     +
Application Insights

The key idea to remember is:

Saga does not make multiple databases behave like one database. It coordinates independent local transactions and uses compensating actions to bring the overall business process to a consistent state.


Don't Copy

Protected by Copyscape Online Plagiarism Checker