dotnet-cqrs/docs/event-streaming/sagas/README.md

144 lines
3.7 KiB
Markdown

# Sagas
Long-running workflows with compensation logic for distributed transactions.
## Overview
Sagas coordinate multiple steps in a workflow, with compensation logic to handle failures. They listen to events, execute business logic, and publish new events to continue the workflow.
**Key Features:**
-**ISaga** - Interface for saga implementations
-**Multi-Step Workflows** - Coordinate complex processes
-**Compensation** - Rollback on failures
-**State Management** - Track saga progress
-**Event-Driven** - React to domain events
## Quick Start
```csharp
public class OrderFulfillmentSaga : ISaga
{
private readonly IEventStreamStore _eventStore;
private readonly IInventoryService _inventoryService;
private readonly IPaymentService _paymentService;
private readonly IShippingService _shippingService;
public async Task HandleAsync(OrderPlacedEvent @event, CancellationToken ct)
{
try
{
// Step 1: Reserve inventory
await _inventoryService.ReserveAsync(@event.OrderId, @event.Items);
await PublishEventAsync(new InventoryReservedEvent { OrderId = @event.OrderId });
// Step 2: Process payment
await _paymentService.ChargeAsync(@event.OrderId, @event.TotalAmount);
await PublishEventAsync(new PaymentProcessedEvent { OrderId = @event.OrderId });
// Step 3: Ship order
await _shippingService.ShipAsync(@event.OrderId);
await PublishEventAsync(new OrderShippedEvent { OrderId = @event.OrderId });
}
catch (Exception ex)
{
// Compensation: Rollback
await CompensateAsync(@event.OrderId);
await PublishEventAsync(new OrderFailedEvent
{
OrderId = @event.OrderId,
Reason = ex.Message
});
}
}
private async Task CompensateAsync(int orderId)
{
// Release inventory
await _inventoryService.ReleaseAsync(orderId);
// Refund payment
await _paymentService.RefundAsync(orderId);
}
private async Task PublishEventAsync(object @event)
{
await _eventStore.AppendAsync("orders", new[] { @event });
}
}
```
## Saga Pattern
```
OrderPlacedEvent
Reserve Inventory
InventoryReservedEvent
Process Payment
PaymentProcessedEvent
Ship Order
OrderShippedEvent
(If any step fails → Compensate all previous steps)
```
## Features
### [Saga Pattern](saga-pattern.md)
Understand the saga pattern and when to use it.
### [Creating Sagas](creating-sagas.md)
Implement ISaga for long-running workflows.
### [Compensation](compensation.md)
Handle failures with rollback logic.
## Common Use Cases
**Order Fulfillment:**
```
Place Order → Reserve Inventory → Charge Payment → Ship Order
(Compensation: Release Inventory → Refund Payment)
```
**User Registration:**
```
Register → Send Verification Email → Wait for Confirmation → Activate Account
(Compensation: Delete User → Cancel Email)
```
**Booking System:**
```
Book Flight → Reserve Hotel → Charge Payment → Send Confirmation
(Compensation: Cancel Flight → Cancel Hotel → Refund Payment)
```
## Best Practices
### ✅ DO
- Implement compensation for each step
- Use idempotent operations
- Store saga state
- Monitor saga completion
- Test failure scenarios
### ❌ DON'T
- Don't forget compensation logic
- Don't assume steps always succeed
- Don't skip state persistence
- Don't create circular dependencies
## See Also
- [Event Streaming Overview](../README.md)
- [Events and Workflows](../fundamentals/events-and-workflows.md)
- [Projections](../projections/README.md)