Claude
Skills
Sign in
Back

saga-patterns

Included with Lifetime
$97 forever

Distributed transaction patterns using orchestration and choreography

General

What this skill does


# Saga Patterns Skill

## When to Use This Skill

Use this skill when:

- **Saga Patterns tasks** - Working on distributed transaction patterns using orchestration and choreography
- **Planning or design** - Need guidance on Saga Patterns approaches
- **Best practices** - Want to follow established patterns and standards

## Overview

Design distributed transaction patterns using orchestration and choreography for microservices.

## MANDATORY: Documentation-First Approach

Before designing sagas:

1. **Invoke `docs-management` skill** for saga patterns
2. **Verify patterns** via MCP servers (perplexity, context7)
3. **Base guidance on established microservices patterns**

## Saga Fundamentals

```text
Why Sagas?

PROBLEM:
Distributed transactions across services are complex.
Traditional 2PC (Two-Phase Commit) doesn't scale.

SOLUTION:
Saga = Sequence of local transactions
Each step has a compensating action
Eventual consistency instead of ACID

┌─────────┐    ┌─────────┐    ┌─────────┐
│ Step 1  │───►│ Step 2  │───►│ Step 3  │
│ Tx + Cx │    │ Tx + Cx │    │ Tx + Cx │
└─────────┘    └─────────┘    └─────────┘
     │              │              │
     ▼              ▼              ▼
   Local         Local          Local
 Transaction  Transaction    Transaction

Tx = Forward Transaction
Cx = Compensating Transaction
```

## Saga Coordination Styles

### Choreography (Event-Driven)

```text
Choreography Pattern:

Services communicate through events.
No central coordinator.
Each service knows what to do next.

┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│   Order     │    │  Payment    │    │  Inventory  │
│   Service   │    │  Service    │    │  Service    │
└──────┬──────┘    └──────┬──────┘    └──────┬──────┘
       │                  │                  │
       │ OrderCreated     │                  │
       │─────────────────►│                  │
       │                  │ PaymentProcessed │
       │                  │─────────────────►│
       │                  │                  │ InventoryReserved
       │◄─────────────────┼──────────────────│
       │ OrderConfirmed   │                  │

Characteristics:
✓ Loose coupling
✓ Simple services
✗ Hard to track
✗ Cyclic dependencies risk
```

### Orchestration (Coordinator-Driven)

```text
Orchestration Pattern:

Central orchestrator coordinates the saga.
Services expose commands.
Orchestrator manages state.

                ┌─────────────────┐
                │   Orchestrator  │
                │  (Saga Manager) │
                └────────┬────────┘
                         │
        ┌────────────────┼────────────────┐
        │                │                │
        ▼                ▼                ▼
┌─────────────┐  ┌─────────────┐  ┌─────────────┐
│   Order     │  │  Payment    │  │  Inventory  │
│   Service   │  │  Service    │  │  Service    │
└─────────────┘  └─────────────┘  └─────────────┘

Characteristics:
✓ Clear flow visibility
✓ Easier debugging
✗ Single point of failure
✗ Coupling to orchestrator
```

## Choreography Implementation

### Event-Driven Flow

```csharp
// Order Service - Starts Saga
public class OrderService
{
    private readonly IEventPublisher _events;

    public async Task CreateOrderAsync(CreateOrderCommand cmd)
    {
        var order = new Order(cmd.CustomerId, cmd.Items);
        await _repository.SaveAsync(order);

        // Publish event to start saga
        await _events.PublishAsync(new OrderCreated
        {
            OrderId = order.Id,
            CustomerId = cmd.CustomerId,
            TotalAmount = order.TotalAmount
        });
    }

    // Handle compensation
    public async Task HandleAsync(PaymentFailed @event)
    {
        var order = await _repository.GetAsync(@event.OrderId);
        order.Cancel("Payment failed");
        await _repository.SaveAsync(order);

        await _events.PublishAsync(new OrderCancelled
        {
            OrderId = @event.OrderId,
            Reason = "Payment failed"
        });
    }
}

// Payment Service - Reacts to OrderCreated
public class PaymentService
{
    public async Task HandleAsync(OrderCreated @event)
    {
        try
        {
            var payment = await ProcessPaymentAsync(@event.OrderId, @event.TotalAmount);

            await _events.PublishAsync(new PaymentProcessed
            {
                OrderId = @event.OrderId,
                PaymentId = payment.Id
            });
        }
        catch (PaymentException ex)
        {
            await _events.PublishAsync(new PaymentFailed
            {
                OrderId = @event.OrderId,
                Reason = ex.Message
            });
        }
    }
}

// Inventory Service - Reacts to PaymentProcessed
public class InventoryService
{
    public async Task HandleAsync(PaymentProcessed @event)
    {
        try
        {
            await ReserveInventoryAsync(@event.OrderId);

            await _events.PublishAsync(new InventoryReserved
            {
                OrderId = @event.OrderId
            });
        }
        catch (InsufficientInventoryException)
        {
            // Trigger compensation
            await _events.PublishAsync(new InventoryReservationFailed
            {
                OrderId = @event.OrderId
            });
        }
    }

    // Compensating action
    public async Task HandleAsync(OrderCancelled @event)
    {
        await ReleaseInventoryAsync(@event.OrderId);
    }
}
```

## Orchestration Implementation

### Saga Orchestrator

```csharp
// Saga State Machine
public class OrderSaga : Saga<OrderSagaData>,
    IAmStartedBy<OrderCreated>,
    IHandle<PaymentProcessed>,
    IHandle<PaymentFailed>,
    IHandle<InventoryReserved>,
    IHandle<InventoryReservationFailed>
{
    protected override void ConfigureHowToFindSaga(SagaPropertyMapper<OrderSagaData> mapper)
    {
        mapper.MapSaga(s => s.OrderId)
            .ToMessage<OrderCreated>(m => m.OrderId)
            .ToMessage<PaymentProcessed>(m => m.OrderId)
            .ToMessage<PaymentFailed>(m => m.OrderId)
            .ToMessage<InventoryReserved>(m => m.OrderId)
            .ToMessage<InventoryReservationFailed>(m => m.OrderId);
    }

    public async Task Handle(OrderCreated message, IMessageHandlerContext context)
    {
        Data.OrderId = message.OrderId;
        Data.CustomerId = message.CustomerId;
        Data.TotalAmount = message.TotalAmount;
        Data.Status = SagaStatus.Started;

        // Request payment
        await context.Send(new ProcessPaymentCommand
        {
            OrderId = message.OrderId,
            Amount = message.TotalAmount
        });
    }

    public async Task Handle(PaymentProcessed message, IMessageHandlerContext context)
    {
        Data.PaymentId = message.PaymentId;
        Data.Status = SagaStatus.PaymentCompleted;

        // Request inventory reservation
        await context.Send(new ReserveInventoryCommand
        {
            OrderId = message.OrderId
        });
    }

    public async Task Handle(PaymentFailed message, IMessageHandlerContext context)
    {
        Data.Status = SagaStatus.Failed;

        // Compensate: Cancel order
        await context.Send(new CancelOrderCommand
        {
            OrderId = message.OrderId,
            Reason = "Payment failed"
        });

        MarkAsComplete();
    }

    public async Task Handle(InventoryReserved message, IMessageHandlerContext context)
    {
        Data.Status = SagaStatus.Completed;

        // Complete the saga
        await context.Publish(new OrderCompleted
        {
            OrderId = Data.OrderId
        });

        MarkAsComplete();
    }

    public async Task Handle(InventoryReservationFailed message, IMessageHandlerContext context)
    {
        Data.Status = SagaStatus.Failed;

        // Compensate: Refund payment
        await context.Send(new RefundPaymentCommand
        {
            OrderId = Data.OrderId,
            PaymentId = Data.PaymentId
        });

        // Compens

Related in General