You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A transport that needs only Postgres, a database-as-queue approach similar to pg-boss in Node. This lowers the barrier to entry: users can start with the database they already have, get the outbox in the same transaction for free, and move to a broker later.
Queue tables with SELECT ... FOR UPDATE SKIP LOCKED, and LISTEN/NOTIFY for low latency.
Package:PostgresTransport, exported from @node-ts/bus-postgres.
Tables: shared, in the configured schema: transport_messages (keyed by queue), transport_queues, transport_subscriptions, transport_dead_letters.
Pub/sub:provision() writes the queue row and a subscription row per handled message (and custom-handler topic). It never deletes any. send and publish both fan out with one insert per subscriber, in one statement. sendToAddress inserts into the target queue.
Receiving: a lease. A short for update skip locked claim sets visible_at = now() + visibilityTimeout (default 30 s, configurable, no heartbeat) and a new lease token. A crashed process's message comes back when its lease ends. failedAttempts is deliveries − 1, like SQS.
Latency:LISTEN/NOTIFY on a dedicated connection, with a 1 s poll as the fallback. listen: false for PgBouncer in transaction mode.
Retries and dead letters:returnMessage sets visible_at. fail moves the row to transport_dead_letters with the bus-failure header. Redrive and purge are documented as SQL.
Delayed delivery: uses the existing outgoing-messages dispatcher. No bus-core change.
Activity
npm create bus-apptemplates #269examples/with docker compose #252adenhertog commentedon Oct 7, 2026
Accepted design (maintainer, 2026-10-07)
PostgresTransport, exported from@node-ts/bus-postgres.transport_messages(keyed by queue),transport_queues,transport_subscriptions,transport_dead_letters.provision()writes the queue row and a subscription row per handled message (and custom-handler topic). It never deletes any.sendandpublishboth fan out with one insert per subscriber, in one statement.sendToAddressinserts into the target queue.for update skip lockedclaim setsvisible_at = now() + visibilityTimeout(default 30 s, configurable, no heartbeat) and a new lease token. A crashed process's message comes back when its lease ends.failedAttemptsis deliveries − 1, like SQS.LISTEN/NOTIFYon a dedicated connection, with a 1 s poll as the fallback.listen: falsefor PgBouncer in transaction mode.returnMessagesetsvisible_at.failmoves the row totransport_dead_letterswith thebus-failureheader. Redrive and purge are documented as SQL.withOutbox()transaction) is a follow-up: postgres transport: exactly-once by enlisting the transport in the outbox transaction #343.provision()creates,initialize()only checks, and the plan has SQL grants for the runtime role.transportTests,outboxTestsandinboxTestsrun against it.