ACME HQDemo work items and pages, made up for Emargen's demo. Not a real company.
Engineering / Engineering / Architecture overview

Events and the outbox

By Marek Nowak · created 17 May 2021, 13:00 UTC · last updated 4 Aug 2026, 09:25 UTC · version 9

eventsoutboxidentity-servicenotifier

identity-service tells the rest of the world about changes through events. It never calls another service in the middle of a transaction. Why: ADR-004.

How it works

  1. A change and its event are written in the same database transaction. The event goes into outbox_events (event_id, client_id, type, payload, attempts, next_attempt_at, delivered_at, last_error).
  2. DeliverOutboxEvents (php artisan events:deliver) runs every minute, takes the waiting rows oldest first and posts each one to notifier's POST /events, signed with an HMAC of the body (X-Acme-Signature: t=...,v1=...). It sets delivered_at; a failed post is tried again after 1, 2, 4, 8 … minutes, at most an hour apart, ten times in all.
  3. Delivery is at least once, so notifier ignores an event id it has already handled.
  4. Once notifier has a phone code, the code is blanked in the row; delivered rows stay in the table.

If delivery stops, nothing is lost: events pile up in outbox_events and go out when it restarts. The outbox lag alarm fires when the oldest undelivered row is older than five minutes (Monitoring and alerts).

Events

TypeSent whenPayload (besides ids)
RequestSubmittedsomeone asks for accessthe request (depot, items or bundle, reason), the person, who it waits on, the client's administrators
RequestDecidedan approver or an administrator approves or declinesthe decision, the note, who decided, the person who asked
ReminderDuethe hourly reminder job finds a request waiting 24 hours, then each day afterthe request, how long it has waited, who it waits on
DepotSsoEnableda depot's single sign-on is switched onthe depot, who switched it, its people and manager
PhoneCodeRequesteda depot worker asks for a sign-in codethe phone number, the code and when it expires

Closing a request after 14 days writes no event: nobody is told when a request expires. That is a product decision waiting to be made, not a bug in the outbox.

Rules

Change history

VersionDateWhoWhat
72 Jun 2025Marekaccess_request.expired
822 Jul 2026Noor, MarekReminder events
94 Aug 2026ElifIn-app notices read the same events