Repository navigation
retry: let the innermost retry interceptor set the attempt timeout - #154
Merged
Merged
Conversation
#152 put the attempt timeout before the caller's options so a caller's timeout wins. A retry interceptor nested inside another one then took the outer one's timeout for a caller's, and the outer timeout won. The outermost retry interceptor now passes the caller's own timeout down in the context. Without one, the innermost interceptor's timeout wins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
milos-lk
approved these changes
Oct 7, 2026
1 task
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.
A retry interceptor nested inside another one sets the attempt timeout again, and a timeout the caller sets still wins over both. This fixes livekit/livekit#4955.
Who sets the timeout
A request goes through the client's interceptors in the order they were added. The first one added runs first and wraps the rest:
Each retry interceptor adds its attempt timeout to the request options. At the send, the options apply in order, so the last timeout in the list is used. In the protocol egress client, the generic retry comes from
psrpc.timeout(300 ms in the issue), and the egress retry inside it uses 10 s, then 20 s and 40 s.What #152 fixed
Each interceptor added its timeout at the end of the list. That overrode a timeout the caller set:
#152 put the interceptor's timeout at the front instead, so a caller's timeout comes later and wins.
Where #152 broke
An inner interceptor cannot tell the outer interceptor's timeout from a caller's. With no caller timeout:
The generic timeout now beat the egress one. Every StartEgress attempt timed out before a worker was picked, and the call failed after about 17 s.
The fix
Only the outermost retry interceptor sees the caller's options alone. It checks whether the caller set a timeout and passes the answer down in the context. If the caller set one, no interceptor adds its own. If not, each interceptor adds its timeout at the end, so the innermost one wins:
TestNestedInnermostTimeoutWinsfails without the fix.🤖 Generated with Claude Code