swap-outbox-source
Replace the outbox relay's polling with change data capture (logical replication, Debezium). Use when the user decides outbox polling load or event latency needs it, or asks about CDC for domain event
Files1
View on GitHubSKILL.md.claude/skills/swap-outbox-source/SKILL.md
GitHubSwap the outbox source
There is no interface for this yet: the replaceable unit is the relay itself,
OutboxRelay in apps/worker/src/outbox/relay.service.ts, which feeds the EventBus.
- Today: each pass claims unpublished rows from every
<schema>.outbox_eventlisted inapps/worker/src/outbox/sources.tswithFOR UPDATE SKIP LOCKED, publishes them, and stampspublished_at. It wakes onNOTIFY(a direct connection) and polls as a fallback. Any number of worker replicas can run it. - Env:
WORKER_DATABASE_DIRECT_URL(LISTEN),RELAY_BATCH_SIZE,RELAY_POLL_INTERVAL_MS(apps/worker/src/env.ts).
Swap
- A CDC reader (a logical replication slot on the outbox tables, or Debezium) that
hands each committed row to
EventBus.publishas anEventEnvelope(same parsing as the relay: unknown event names are passed through, not dropped). - Replace
OutboxRelayinapps/worker/src/outbox/outbox.module.tswith it.emitEvent, the outbox tables and every consumer stay as they are. - Retention: the
outbox-retentionmaintenance job purges rows bypublished_at, so the reader must still stamp it, or retention must change to match. - Replication needs a role with
REPLICATIONand a slot per environment: a migration can't grant that; it'sinfra/postgres/initlocally and OpenTofu or CloudNativePG in clusters. An abandoned slot holds WAL forever: monitor it.
Tests
The outbox relay tests in apps/worker/test/worker.integration.test.ts (delivery,
crash and redelivery, several relays at once) must pass unchanged against the new source.
Finish
- The verify skill.
- Ask the
revieweragent to review the change, and thesecurity-revieweragent: a new implementation brings its own credentials and sends data somewhere new. If you wrote a migration, themigration-revieweragent too. - Update the seam's row in the README's "Scaling path" table if what's "Now" changed.