In this lesson, you will learn how to maintain data integrity across multiple services or databases by implementing the Saga pattern, avoiding the pitfalls of traditional distributed transactions.
The Problem with Distributed Transactions
In a monolithic application, we rely on System.Transactions or TransactionScope to ensure that if one part of a process fails, the entire operation rolls back. However, in a distributed system involving multiple databases or microservices, holding locks across network boundaries leads to performance bottlenecks and reliability issues. Instead of trying to "lock" everything at once, we use the Saga Pattern.
The Saga Pattern
A Saga is a sequence of local transactions. Each local transaction updates the database and publishes a message or event to trigger the next step. If a step fails, the Saga executes compensating transactions—a series of "undo" operations that revert the changes made by the preceding successful steps.
Think of an E-commerce "Order Process":
- Service A (Inventory): Deduct stock.
- Service B (Payment): Charge the customer.
- Failure: If Payment fails, Service A must perform a compensating action to re-add the stock.
Implementation Concept
In C#, you typically manage this using a message broker. Your EF Core DbContext plays a crucial role: you must save the business state and the outgoing integration event in the same local transaction.
// Example of a local transaction in EF Core
using var transaction = context.Database.BeginTransaction();
try {
// 1. Update local database
context.Inventory.Update(item);
// 2. Save event to an "Outbox" table in the same DB
context.OutboxMessages.Add(new OutboxMessage {
Type = "InventoryReserved",
Payload = serializedEvent
});
context.SaveChanges();
transaction.Commit();
} catch {
transaction.Rollback();
}
By ensuring that the business entity update and the event record are committed together in one DbContext operation, you guarantee that the next service in the chain will eventually receive the notification, even if the system crashes immediately after. This "eventual consistency" model allows your services to remain decoupled and highly available.
Key Takeaway: Since distributed locks are impractical, use the Saga pattern to chain local transactions and implement compensating logic to gracefully undo partial operations when a step fails.