fix(outbox): let a failed row finish its retry — version CAS instead of a status list
A `failed` row is scheduled for retry, not settled: claimDue() selects it on purpose. Listing it in TERMINAL_OUTBOX_STATUSES (#109) meant the retry could never complete — claimDue re-selected the row, publish succeeded, markSent() refused to touch it, so the status stayed `failed`, `attempts` never grew (so maxAttempts/DLQ never fired), `nextAttemptAt` stayed in the past, and the row was re-claimed on every flush. The returning ACK bounced as message-not-in-flight. Nothing short of a manual dlq could settle it. Reported by @lichtpfad with 766 log lines over two msgIds (#113). The race #109 was guarding — a fast ACK/NACK landing between publish() and markSent(), where the late markSent() drags the settled row back into flight — is now handled per row: claimDue() hands out the row `version`, the flush loop passes it to markSent(), and the update applies only while the row is untouched. That covers any concurrent transition, not just the statuses someone enumerated. TERMINAL_OUTBOX_STATUSES keeps its real meaning: acked and dlq. The ack-hardening assertion on the set's contents is rewritten to state the new rule; the behaviour it protected is covered by the version-CAS tests. Closes #113
A
Alexander Vasiliev committed
55f5a4ed0670a10bf4d11ba3f2dda2e5676a633b
Parent: 7208903