backbone-outbox 2.7.36

Durable transactional-outbox + inbox + relay primitives for go-live exactly-once event delivery over Postgres.
Documentation

backbone-outbox

Durable transactional-outbox + relay + inbox primitives for go-live exactly-once event delivery over Postgres — without a broker. Composes the in-process backbone-messaging bus; does not replace it.

  • outbox::stage(&mut tx, record) — write a serialized event into <schema>.outbox_events in the producer's own transaction, so the state change and the event commit atomically (no lost/phantom events). Idempotent on the event id.
  • relay::drain_once(pool, schema, batch, publish) — drain un-published rows (FOR UPDATE SKIP LOCKED) onto a caller-supplied publish sink and mark them; at-least-once. Host it on a backbone-jobs schedule; wire publish to the in-proc bus today, a broker later.
  • inbox::once(&mut tx, schema, consumer, event_id) — dedup a (consumer, event_id) in the consumer's transaction, turning at-least-once delivery into an exactly-once effect.

Framework plumbing: depends on sqlx + serde only — never on a domain module or the bus. See docs/erp/event-bus-contract.md for the full contract and the rollout checklist.

outbox::migrate(&pool, "payment").await?;                 // create outbox_events + inbox_consumed
// producer:
let mut tx = pool.begin().await?;
// ... mutate state ...
outbox::stage(&mut *tx, "payment", &record).await?;
tx.commit().await?;
// relay:
relay::drain_once(&pool, "payment", 100, |rec| async move { bus.publish(rec).await }).await?;
// consumer:
let mut tx = pool.begin().await?;
if inbox::once(&mut *tx, "billing", "settlement-consumer", event_id).await? { /* apply */ }
tx.commit().await?;