Outbox Lifecycle
How durable outbox ledger rows and hot delivery rows make state-change events publishable, retryable, and idempotent.
Notes
- State workflows insert durable events into
outbox_eventsin the same database operation as the state change. - An insert trigger creates one
outbox_delivery_queuerow for each new event; this is the hot queue scanned by coordinators. - The publisher claims delivery rows with
available_at <= now()andFOR UPDATE SKIP LOCKED, using the sharded delivery queue index for the hot claim path. - A claim assigns a
claim_token, setsclaimed_until, and moves the delivery rowavailable_atinto the future as a publish lease. - Claimed batches are published with bounded concurrency controlled by the coordinator outbox publish parallelism setting.
- RabbitMQ publication declares durable queues and bindings before publish, uses persistent messages, sets the outbox
dedupe_keyas the AMQP message id, publishes with mandatory routing, and waits for publisher confirmation. - Successful publishes mark the ledger event
publishedand delete the delivery row only when the delivery row still has the sameclaim_token; failed publishes clear the claim and return the delivery row to retry with a delay and error message. - Broker delivery is at-least-once. Exactly-once effects are managed by idempotency guards: outbox
dedupe_key, fenced publisher claims, chunk-claim checks, current-attempt authority checks, and evaluator-result uniqueness.