message_outbox holds the original send options for retryable failures. A cron drains it: claims due rows with a compare-and-set so overlapping runs cannot double-send, reclaims 'sending' rows stuck over 15 minutes, replays through the same port facade with a fromOutbox flag, and backs off 5 minutes × 2^attempts up to six attempts before marking the row dead.
Also called: message outbox · failed send retry · network blip · queued messages
- 1A retryable failure (network exception) enqueues the original options.
- 2The cron claims pending rows and stale 'sending' claims.
- 3Each is replayed through sendCustomerEmail / sendCustomerSms with fromOutbox set, so a still-failing send updates the row rather than enqueueing a duplicate.
- 4A send that comes back 'skipped' is marked dead with the reason — retrying cannot fix configuration.
- 5Rows that exhaust attempts become 'dead' and stay visible for ops.
This is one of two deliberate behavioural deltas the ports refactor introduced, recorded in customerMessaging.ts: 'Retryable failures (network-level, request never reached the provider) are persisted to message_outbox instead of being silently lost.' The strict definition of retryable is the safety half — an HTTP rejection means the provider saw the message, so retrying risks texting a customer twice.
- Transient network failures silently lost customer messages.
- Naive retrying would duplicate messages the provider had already accepted.
- A crashed drain run could strand rows in a claimed state forever.
See it on your own jobs
Twenty minutes, your numbers, no slide deck. We’ll build one of your real buildings in front of you and send you the estimate link at the end — yours to keep either way.
or keep browsing features →