Repository navigation
Acknowledge a result the router has already finished with - #13
Merged
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
When a result arrives,
handleMessageacks 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 theif (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()requirespendingAcksto be empty, and both worker threads share onePersistentEventsSender, 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 ininfra/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:
D F F FWhat 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
waitForResulttimeout 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 = 3budget, which remains unexplained.Testing
typecheckandlintclean, 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