Skip to content

Acknowledge a result the router has already finished with - #13

Merged
partouf merged 1 commit into
mainfrom
ack-served-retransmissions
Sep 27, 2026
Merged

partouf merged 1 commit into
mainfrom
ack-served-retransmissions

Conversation

@partouf

@partouf partouf commented Sep 27, 2026

Copy link
Copy Markdown
Member

Why

When a result arrives, handleMessage acks it, unsubscribes, and drops the subscription. If that ack never reaches the worker — lost, or the sender's connection already gone (Failed to send ack … disconnected) — the worker resends 3s later. By then there is no subscription to match, so the message falls off the end of the if (subscription) and is dropped without an ack. The worker cannot distinguish that from "nobody was listening", so it spends its whole retry budget, about 9s, on a result the user already has.

That is not free. isReadyForNewMessages() requires pendingAcks to be empty, and both worker threads share one PersistentEventsSender, so those 9s stop the entire instance pulling from SQS. The queue deepens, more results pass their deadline, and more of them end up back on this same path — the amplifier described in infra/docs/ce-router-failure-atlas.md §5.2, which also recommends exactly this fix.

Measured on prod, in an 85-minute window, orphaned results split as:

pattern count meaning
D F F F 7 delivered, then three pointless resends — this PR
never delivered 9 result never reached the router; unaffected

What this does

Guids the router has served, or given up waiting for, are remembered for two minutes. A retransmission of one is acked and discarded. The worker is then released on its first retry instead of never, cutting each occurrence from ~12s of ack-gate stall to ~3s.

Two minutes clears the longest window a stale retransmission can appear in — the 60s requester deadline plus the worker's ~9s of retries — with room to spare. At prod's 2-3 compiles/s per router that is a few hundred entries, each a guid and a timestamp, pruned from the front on insert.

The waitForResult timeout records the guid too, so a compile that finishes after the router gave up is acked rather than retried into a void. compiler-explorer#9160 already makes the worker give up quickly there, so that half is belt-and-braces.

What this does not fix

Anything where the result never reached the router: the never-delivered cases above, and a separate guid seen resending 104 times over 161 minutes against a maxRetries = 3 budget, which remains unexplained.

Testing

typecheck and lint clean, 7/7 tests, three new: re-ack after serving, no ack for a guid never served, and no ack once the TTL has lapsed.

🤖 Generated with Claude Code

When a result arrives, the router acks it, unsubscribes and drops the subscription. If that ack
never reaches the worker - lost, or the sender's connection already gone - the worker resends 3s
later, finds no subscription to match, and the message is dropped without an ack. So it resends its
whole budget, about 9s, for a result the user already has.

That is not free: isReadyForNewMessages() requires pendingAcks to be empty and both worker threads
share one sender, so those 9s stop the entire instance pulling from SQS. The queue deepens, more
results pass their deadline, and more of them come back to this same path. Seven of sixteen orphans
in an 85-minute prod sample were this.

Guids the router has served or timed out are now remembered for two minutes - clear of the 60s
requester deadline plus the worker's retries - and a retransmission of one is acked and discarded.
Entries are pruned from the front on insert, so the map holds only what is still in flight.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@partouf
partouf merged commit 2a9691f into main Sep 27, 2026
2 checks passed
@partouf
partouf deleted the ack-served-retransmissions branch September 27, 2026 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant