faststream-outbox is a FastStream broker
integration for the transactional outbox pattern — a Postgres table is
the message queue. A producer writes a domain entity and an outbox row in
the same SQLAlchemy transaction; a subscriber polls the table with
FOR UPDATE SKIP LOCKED, runs the handler, and deletes the row on
success. The table is the queue — no separate message bus, no relay
process, no Kafka.
Use it when¶
- You already have Postgres and don't want to add a message bus just to get at-least-once delivery alongside your domain writes.
- You want the row insert to commit atomically with the rest of your SQLAlchemy transaction (no two-phase commit, no Sagas).
- You're building on FastStream or FastAPI and want the same subscriber / dependency-injection ergonomics for an outbox.
- You need a durable, transactionally-published feed of events that a separate worker relays to Kafka / RabbitMQ / NATS with the at-least-once contract preserved end-to-end.
Reach for something else when¶
- You're already running Kafka / Rabbit / NATS and don't need transactional atomicity with a DB write → use that broker directly.
- You need sub-second scheduled-delivery precision → see Timers § latency floor.
- You're on a non-Postgres database → this package is Postgres-only at v0. CDC / Debezium may be a better fit (see Comparison).
- You're modelling ad-hoc background jobs rather than events tied to a DB transaction → see Comparison § vs Celery.
Start where you're going¶
| If you want to… | Start at |
|---|---|
| Install and write the first publisher / subscriber | Installation → Tutorial: Your first outbox app |
| See it work end-to-end on a FastAPI app | FastAPI integration |
| Relay outbox rows to Kafka / RabbitMQ / NATS / Redis | Relay to Kafka / RabbitMQ / NATS |
| Understand the architecture before adopting | How it works |
| Compare against CDC / Kafka transactions / a hand-rolled outbox | Comparison |
| Deploy to production safely | Production checklist |
The categorized index below (also the left-hand nav) lists every page with a one-line summary.
Documentation¶
Getting started¶
- Installation — install, optional
extras (
asyncpg,fastapi,validate,prometheus,opentelemetry), Postgres setup. - Basic usage — declare the table, create the broker, publish a row, register a subscriber.
- Tutorial: Your first outbox app — build a working publisher / subscriber from scratch.
- Tutorial: Add a Kafka relay — extend the first app to forward outbox rows to Kafka.
Concepts¶
- How it works — two-loop subscriber, lease-token invariant, at-least-once semantics, opt-in DLQ on terminal failure.
- Comparison — vs writing your own, vs CDC,
vs Kafka transactions, vs
LISTEN/NOTIFY, vs Celery, vs FastStream foreign-broker direct. - Instrumentation seams — concept: the recorder seam vs native middleware, and why both exist. Read this first if you're deciding what to wire.
Guides¶
- FastAPI integration — the canonical use case:
HTTP routes and outbox subscribers share one
AsyncSession. - Relay to Kafka / RabbitMQ / NATS — forward outbox rows to a real bus with one decorator; at-least-once preserved.
- Timers —
activate_in/activate_at,timer_iddedup,cancel_timer. - Testing —
TestOutboxBrokersync and loop-driven modes. - Schema validation — opt-in
Alembic-driven check for
/healthand CI. - Setup Prometheus and OpenTelemetry — step-by-step: wire the native middleware and recorder adapters end-to-end.
- A messaging service, end-to-end — the relay, timer, and testing guides composed in one service.
Reference¶
- Subscriber — options, ack policies, retry strategies, connection budget, slow-handler queue segregation.
- Publisher —
publish,publish_batch,OutboxPublisher, chained publishing viaOutboxResponse. - Router —
OutboxRouter,OutboxRoute, walking every subscriber viabroker.subscribers. - Dead-letter queue — opt-in audit table, atomicity
via a single CTE,
dlq_writtenmetric, retention patterns. - Observability — reference: the recorder-seam API, the full event/tag catalog, and the operator PromQL playbook.
Operations¶
- Production checklist — connection budget, lease TTL sizing, and deploy-safety items before going live.
- Troubleshooting — common symptoms
(idle latency,
lease_lostspikes, connection exhaustion) and fixes. - Alembic migrations — autogenerate the outbox table and its partial indexes.