Skip to main content

ADR 0006: Centralized outbox relay

Status​

Accepted.

Context​

ADR 0004 put a scheduled relay inside auth. Social then needed the same loop. Per-service relays duplicate logic, split the metrics, and can double-publish if an old and a new relay run together.

Decision​

  1. outbox-relay-service is the publisher. In Java it listens on 8088 inside the container. Compose publishes host 8089 so it does not collide with messaging on host 8088.
  2. shared-outbox provides OutboxWriter / JdbcOutboxWriter for producers and OutboxRelayEngine for the worker.
  3. Producers only insert outbox rows. In-process relays and direct publish from friendship flows are removed.
  4. Claim with FOR UPDATE SKIP LOCKED, publish outside the lock, exponential backoff, dead-letter at max attempts, stuck-lock recovery, graceful shutdown.
  5. Health degrades when lag is over 30 seconds or any dead-letter row exists.

Sources now include auth, social, feed, messaging, and expense. The original ADR listed auth and social; later producers joined the same contract. Adding a producer is a table plus a relay config entry, not a new relay codebase.

Consequences​

One place to scale and alert. Relay downtime delays every side effect. The relay's database user can read and update every producer outbox. That privilege is limited to outbox tables and should stay that way.

Running any legacy in-process relay beside this service double-publishes. Cut over per environment in one step.

Rollback​

Stop the relay. Do not delete rows. Replay after the fix. Re-introducing an in-process relay is not supported in the codebase after this ADR.