Skip to content

0002. Keep the event bus in memory and put durability in outboxes

Context

Modules react to each other through domain events. Some reactions are cheap and local, such as sending a security email when a password changes. Others must not be lost, such as delivering an event to a customer's webhook endpoint or running an automation. A durable bus, persisting every event before any handler runs, would make every emit a database write and add a dispatcher to operate, for the benefit of the minority of consumers that need it.

Options

OptionForAgainst
A persisted bus with a dispatcher and retries for every handlerNothing lost, for any subscriberA write and a queue for every emit; every subscriber must be idempotent; more to run
An external brokerProven delivery guaranteesA new piece of infrastructure for every deployment, which conflicts with running many small instances
An in-memory bus; consumers that need durability write their own outboxEmits stay cheap; durability is paid only where neededEvents can be lost between the emit and the outbox write; each durable consumer builds its own outbox

Decision

The bus in @monark/common stays in process and best-effort: handlers run in order, each isolated so a failure is logged and skipped. Consumers that need durability subscribe with a wildcard and write an outbox row that a worker drains with retries. Webhooks did this first, with at-least-once delivery; automations and achievements followed the same shape. The webhook subscriber registers last so it records the event after every other handler has run.

The deciding reason: only a few consumers need guaranteed delivery, and an outbox per consumer gives them that without making every emit pay for it.

Consequences

  • An event emitted moments before the process dies, before its subscribers run, is lost. Anything that must reach an external system goes through webhooks, not a bus subscriber.
  • Subscribers run inside the emitting request, so a slow subscriber slows the request; heavy work belongs in an outbox worker.
  • The webhook, automation and achievement outboxes are three similar implementations, each with its own worker.