In this lesson, you will learn how to maintain data consistency across microservices by using state machines to coordinate long-running distributed business processes.
When a business process spans multiple services—such as an e-commerce order that involves an Inventory Service, Payment Service, and Shipping Service—you cannot rely on traditional database transactions. If one service fails halfway through, you face a distributed data integrity problem. The Saga Pattern solves this by breaking the process into a sequence of local transactions, coordinated by an orchestrator.
Orchestration via State Machines
Instead of having services "fire and forget," an orchestrator maintains a SagaState. This state machine tracks the progress of the workflow. Each step has a corresponding compensation action—a way to undo the changes if a subsequent step fails.
Consider an OrderSaga orchestrating a payment:
public class OrderSaga : SagaStateMachine<OrderState>
{
public OrderSaga()
{
InstanceState(x => x.CurrentState);
// Define the flow
Initially(
When(OrderPlaced)
.Then(context => context.Saga.OrderId = context.Message.OrderId)
.TransitionTo(ProcessingPayment)
.Send(new ProcessPaymentCommand()));
// Handle failure with compensation
During(ProcessingPayment,
When(PaymentFailed)
.Then(context => UndoInventoryReservation(context))
.TransitionTo(Cancelled));
}
}
The orchestrator acts as the "brain." When the PaymentService emits a PaymentFailed event, the Saga intercepts it. Because the orchestrator knows exactly which steps have already completed, it can trigger the UndoInventoryReservation command to revert the system to a consistent state.
Why use State Machines?
By using a state machine, you eliminate "spaghetti" code where every service needs to know about every other service's failure scenarios. The state machine provides:
- Visibility: You can query the saga to see exactly where a process is stuck.
- Resilience: If a service is down, the saga can retry the message or escalate based on the current state.
- Consistency: It guarantees that you eventually reach a terminal state, either
CompletedorCancelled, ensuring your distributed system remains in sync without locking databases.
Key Takeaway: The Saga pattern uses state-aware orchestration to manage distributed workflows, ensuring that partial failures are handled by executing explicit compensation logic to maintain system-wide data integrity.