Outbox, Inbox & Saga Patterns
Relevant source files
The following files were used as context for generating this wiki page:
The Forze framework implements the Outbox, Inbox, and Saga patterns to ensure reliable communication and data consistency in distributed systems. These patterns collectively handle transactional message delivery, exactly-once processing, and complex multi-step business logic orchestration.
The system uses a Checkout Saga to coordinate between different aggregates, while the Transactional Outbox guarantees that integration events are only dispatched if the local transaction succeeds. The Inbox pattern then ensures that these events are processed by downstream consumers exactly once.
Sources: examples/README.md:27-35, skills/forze-wiring/SKILL.md:188-198
Transactional Outbox Pattern
The Transactional Outbox pattern ensures that a service can atomically update its database and send messages/events. Events are persisted in an "outbox" table within the same database transaction as the business state change.
Components and Flow
- OutboxSpec: Defines the logical configuration for an outbox, including the destination (queue or channel) and the codec used for serialization.
- Outbox Relay: A background worker or process that "relays" staged messages from the outbox storage to the actual message broker (e.g., SQS or RabbitMQ).
- Outbox Destination: Specifies where the relayed message should go, such as a specific queue route and channel.
The diagram shows how the local database transaction encapsulates both the state change and the message staging.
Sources: src/forze/application/contracts/outbox/specs.py:6-24, src/forze_kits/integrations/outbox/relay.py:1-15, examples/README.md:27-31
Outbox Configuration
| Field | Type | Description |
|---|---|---|
name | str | Logical route name for the outbox. |
destination | OutboxDestination | Target queue route and channel for the relay. |
codec | Codec | Serializer used for the message payload. |
Sources: src/forze/application/contracts/outbox/specs.py:27-35
Inbox Pattern
The Inbox pattern provides exactly-once processing for incoming messages. It tracks the IDs of processed messages to prevent duplicate processing if a message is redelivered by the broker.
Processing Logic
When a consumer receives a message, it checks the InboxSpec to verify if the message has already been handled. If not, it executes the handler and marks the message as processed within a local transaction.
This flow ensures that even if the network fails after processing but before acknowledgment, the message will not be re-processed upon redelivery.
Sources: src/forze/application/contracts/inbox/specs.py:1-15, examples/README.md:33-35
Saga Pattern
The Saga pattern manages distributed transactions by breaking them into a series of local transactions. Forze uses a Saga Coordinator to manage this orchestration.
Checkout Saga and Orchestration
A Checkout Saga typically follows a "reserve → confirm" pivot model. It coordinates actions across multiple aggregates. If a step fails, the saga triggers compensation logic (e.g., releasing reserved inventory).
Transactional Integration
Sagas are integrated into the operation pipeline using stage hooks. Developers can use outbox_flush_tx_on_success_factory to ensure the outbox is flushed only when the saga step completes successfully.
Sources: skills/forze-wiring/SKILL.md:188-198
Implementation Summary
| Pattern | Primary File | Key Responsibility |
|---|---|---|
| Outbox | specs.py (Outbox) | Atomic staging of outbound messages. |
| Inbox | specs.py (Inbox) | Idempotent/Exactly-once message consumption. |
| Saga | coordinator.py | Multi-aggregate orchestration and compensation. |
| Relay | relay.py | Moving staged outbox messages to the broker. |
Sources: src/forze/application/contracts/outbox/specs.py, src/forze/application/contracts/inbox/specs.py, src/forze/application/contracts/saga/coordinator.py, src/forze_kits/integrations/outbox/relay.py
The Forze framework provides these patterns as reusable primitives. By combining the OutboxSpec with the SagaCoordinator, applications achieve high reliability in distributed environments, ensuring that aggregate state and integration events remain synchronized even during infrastructure failures.
Sources: examples/README.md:42-45, skills/forze-wiring/SKILL.md:200-205