Commit 68aed04
committed
fix(plugin-email): sweep sys_email rows stranded at queued, and report a failed drain at error (#5161)
`status:'queued'` had exactly one consumer — the afterInsert outbox drain that
fires during the insert itself (plus, since #5160, the email.send.async job
send() publishes). A process that died between the insert and the delivery, or
a drain whose delivery threw, left the row at `queued` forever: a state named
after a queue with no reader, with the caller already told the message was
accepted.
- `sweepStrandedOutbox` runs once per boot at kernel:ready, after the queue
subscriber and the #5160 boot gate. Queue mode publishes `{ rowId }` through
EmailService.enqueuePersistedRow (send()'s own producer, options and
`sys_email:<id>` idempotency key, so a row with a pending job collapses onto
it); inline mode finalizes the row in place via deliverPersistedRow.
- Only rows older than OUTBOX_SWEEP_MIN_AGE_MS (5m) are eligible — a young row
is somebody's in-flight work, on this instance or a sibling, and age is the
only property that means the same thing on every instance. Service-managed
rows and rows carrying a message_id are skipped. Batch bounded at 500,
oldest first, truncation reported.
- Boot does not await the sweep; it self-catches and reports at error, since a
throwing kernel:ready handler is swallowed on LiteKernel (#5170).
- Both drain-hook catches now log at error with the consequence (the message
was NOT sent, the row stays at `queued`) and the fix, per the AGENTS.md
degradation-log-level rule, and deliverPersistedRow joins
DURABILITY_CRITICAL_CALLEES so the level cannot regress.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017MCKJaEomEqg4tvz4SzdNd1 parent 9c4f174 commit 68aed04
8 files changed
Lines changed: 1048 additions & 2 deletions
File tree
- .changeset
- packages/plugins/plugin-email/src
- scripts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
0 commit comments