Relay Strategies
nats-outbox is designed with pluggable strategies for how the Relay extracts events from the database.
Currently, the V1 architecture relies on a highly optimized Polling strategy. A WAL (Write-Ahead Log) Tailing strategy is planned for V2.
V1 — The Polling Strategy
To start the relay with the polling strategy (currently the only available strategy and the default):
How it works: Drain-then-Sleep
The polling strategy uses a single asynchronous event loop to query the outbox_events table. However, it does not sleep blindly. It uses a Drain-then-Sleep pattern to optimize for both high throughput and low database load:
- The relay queries for a batch of
pendingevents (limited byOUTBOX_BATCH_SIZE). - If it finds events, it processes them, marks them as
published, and immediately loops to query again (zero sleep). It drains the queue as fast as Postgres and NATS can handle. - Only when a query returns
0events does the relay go to sleep forOUTBOX_POLLING_INTERVALseconds.
Concurrency: SELECT FOR UPDATE SKIP LOCKED
The hot query executed by the relay looks like this:
SELECT * FROM outbox_events
WHERE status = 'pending' AND scheduled_at <= now()
ORDER BY scheduled_at, id
LIMIT batch_size
FOR UPDATE SKIP LOCKED
The SKIP LOCKED clause is what allows you to run multiple instances of the Relay concurrently. When an instance selects a batch of rows, it acquires a row-level write lock on them. If another relay instance executes the query at the exact same moment, it simply skips the locked rows and fetches the next available batch.
Summary of V1 (Polling)
| Feature | Details |
|---|---|
| Latency | Up to OUTBOX_POLLING_INTERVAL (default 1s) when idle. Near-zero when under load. |
| DB load | Constant light read load. Strongly mitigated by the partial B-tree index on (status) WHERE status='pending'. |
| Ordering | FIFO within a single relay. Weakened under concurrent relay instances due to SKIP LOCKED. |
| Complexity | Very Low. Does not require Postgres superuser or replication slots. |
V2 — WAL Tailing (Planned)
The V2 strategy will use PostgreSQL's Logical Replication (pgoutput via psycopg3).
Instead of querying the table, the relay will stream the PostgreSQL Write-Ahead Log (WAL) directly. When a COMMIT happens in your application, the relay will receive the event instantly without polling.
Summary of V2 (WAL)
| Feature | Details |
|---|---|
| Latency | Sub-millisecond. Reacts to the WAL INSERT in real-time. |
| DB load | Zero read polling. The replication slot streams data directly. |
| Ordering | Strict total order by LSN (Log Sequence Number). |
| Complexity | High. Requires wal_level=logical, a REPLICATION user privilege, and management of replication slots. |