Category: Distributed Transactions / Microservices
Problem: How to maintain data consistency across multiple microservices without 2PC (two-phase commit).
Solution: Break long transactions into a series of local transactions. Each has a compensating action (undo) if something fails.

🔑 Key Points

🖥️ C# Example – E-Commerce Order (Orchestration Saga)

Scenario:

  1. Place Order

  2. Reserve Payment

  3. Update Inventory

  4. If failure → rollback via compensating transactions

// Step definitions
public interface ISagaStep
{
    Task ExecuteAsync();
    Task CompensateAsync();
}

public class PaymentStep : ISagaStep
{
    public async Task ExecuteAsync() => Console.WriteLine("✅ Payment Reserved");
    public async Task CompensateAsync() => Console.WriteLine("❌ Payment Refunded");
}

public class InventoryStep : ISagaStep
{
    public async Task ExecuteAsync() => Console.WriteLine("✅ Inventory Updated");
    public async Task CompensateAsync() => Console.WriteLine("❌ Inventory Restored");
}

// Orchestrator
public class SagaOrchestrator
{
    private readonly List<ISagaStep> _steps = new();
    public void AddStep(ISagaStep step) => _steps.Add(step);

    public async Task ExecuteAsync()
    {
        var executedSteps = new Stack<ISagaStep>();
        try
        {
            foreach (var step in _steps)
            {
                await step.ExecuteAsync();
                executedSteps.Push(step);
            }
            Console.WriteLine("🎉 Saga Completed Successfully!");
        }
        catch
        {
            Console.WriteLine("⚠️ Error! Starting Compensation...");
            while (executedSteps.Count > 0)
                await executedSteps.Pop().CompensateAsync();
        }
    }
}

Usage:

var saga = new SagaOrchestrator();
saga.AddStep(new PaymentStep());
saga.AddStep(new InventoryStep());
await saga.ExecuteAsync();

🌍 Real-World Example

📌 Remember in Interview