Core Concepts Overview
Understanding the fundamentals of saga orchestration with Saga Bus.
What is a Saga?​
A saga is a long-running business process that spans multiple services or steps. Unlike a traditional database transaction, sagas handle distributed operations by:
- Breaking complex workflows into discrete steps
- Maintaining state across those steps
- Handling failures with compensation (undo operations)
- Reacting to events from multiple sources
The Saga Pattern​
Key Components​
Messages​
Messages are the events and commands that drive sagas. Every message has a type property:
interface OrderSubmitted {
type: 'OrderSubmitted';
orderId: string;
customerId: string;
total: number;
}
Saga State​
Each saga instance maintains state that persists across message handling:
interface OrderState extends SagaState {
orderId: string;
status: 'pending' | 'confirmed' | 'shipped';
total: number;
}
Correlation​
Correlation links messages to the correct saga instance. Typically by a business identifier:
.correlate('OrderSubmitted', msg => msg.orderId, { canStart: true })
.correlate('PaymentCaptured', msg => msg.orderId)
Learn more about Correlation →
Transport​
The transport handles message delivery between services:
const transport = new RabbitMqTransport({
url: 'amqp://localhost',
});
Store​
The store persists saga state to a database:
const store = new PostgresSagaStore({
connectionString: process.env.DATABASE_URL,
});
Bus​
The bus wires everything together:
const bus = createBus({
transport,
store,
sagas: [{ definition: orderSaga }],
});
Saga Lifecycle​
Optimistic Concurrency​
Saga Bus uses version-based optimistic concurrency to prevent lost updates:
// State includes metadata
interface SagaState {
metadata: {
sagaId: string;
version: number; // Incremented on each update
createdAt: Date;
updatedAt: Date;
isCompleted: boolean;
};
}
If two handlers try to update the same saga simultaneously, one will fail with a ConcurrencyError and retry.
Learn more about State Management →
Error Handling​
Saga Bus distinguishes between:
- Transient errors - Temporary failures (network, timeout) that should retry
- Permanent errors - Business logic failures that need compensation
- Validation errors - Invalid messages that should be rejected
Learn more about Error Handling →
Timeouts​
Set timeouts to handle cases where expected events never arrive:
.on('OrderSubmitted')
.handle(async (msg, state, ctx) => {
ctx.setTimeout(30 * 60 * 1000); // 30 minutes
// ...
})
.on('SagaTimeoutExpired')
.handle(async (msg, state, ctx) => {
// Handle timeout - maybe cancel the order
})
Distributed Tracing​
Saga Bus propagates W3C trace context automatically:
// Trace context flows through
ctx.publish({ type: 'NextStep', ... });
// ↑ Automatically includes traceparent header
Learn more about Distributed Tracing →
Next Steps​
- Messages - Deep dive into message design
- Sagas - Understanding saga state
- Correlation - Linking messages to sagas
- DSL Reference - Complete API reference