mirror of
https://gh-proxy.org/https://github.com/klinsmaya/multica.git
synced 2026-11-08 17:36:45 +08:00
A relayed reply used to be counted once per delivery attempt: a reply that failed before the wire and was re-offered recorded a drop on every offer, and one that later succeeded was counted delivered as well. The outcome is now recorded once, after the last offer, by the single owner that can know it. Settling it once takes an at-most-once claim that survives every partial failure the store can produce: - Claims are token-fenced through Lua compare-and-act, so a command the client re-sends after a lost response can never act on a claim a later owner holds. - An error from Release or Settle means the outcome is UNKNOWN, never "did not happen". Release is resolved by the next offer's Claim; Settle has no later offer to resolve it, so it is retried — bounded, and idempotent. - The publisher's end-of-grace Resolve fences a claim nobody settled, so a holder that comes back records nothing and the reply keeps one record. - outcomeGrace covers both store round trips per offer, so it cannot expire while the chain is still running. The retry lives inside the shutdown budget. Release and Settle still ignore plain cancellation — a frame already in the user's chat has to have its claim settled — but they inherit a bounding deadline, and the loop opens no new attempt once one has passed. Those deadlines reach the wire only because the claim store gets its own Redis client: go-redis discards context deadlines unless ContextTimeoutEnabled is set, and setting it on the shared relay client would change the timeout behaviour of every realtime publish. One boundary is deliberately accepted and now stated in the code, the log and a test: a store that keeps losing settle responses can leave a delivered reply with no outcome recorded. Recording it instead would double the far more common case. That is a monitoring gap under a failing store, not a reply the user did not get.