tp: keep polling until the caller's deadline - #46
Merged
Merged
Conversation
The poll backoff doubles without bound, so it regularly grows past what is left of the caller's context. The client then sleeps through the rest of its own budget without asking the third party again and returns context.DeadlineExceeded for a discharge that may have been ready for most of that window. With the default backoff under a 30 second deadline, polls land at t=0,1,3,7,15 and the next one is scheduled for t=31: nothing is polled for the second half of the budget. Clamp the wait when the next backoff would sleep past the deadline, so a final poll still lands before the context expires. The clamp only ever shortens a wait, and the backoff keeps growing from its unclamped value, so a caller's schedule is unchanged except for that last poll. Also drop the copy of defaultBackoff inlined in nextBO. It is unreachable, since NewClient always assigns pollBackoffNext, and a change made there silently does nothing.
This was referenced Aug 24, 2026
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.
The third party poll loop backs off without an upper bound, so the interval
routinely grows past what is left of the caller's context. When it does, the
client sleeps through the rest of its own budget without asking the third party
again, and then reports
context deadline exceededfor a discharge that mayhave been ready for most of that window.
doPollnow clamps the wait when thenext backoff would sleep past the deadline, so a final poll always lands before
the context expires.
Context
With the default backoff under a 30 second deadline, polls land at
t=0,1,3,7,15 and the next one is scheduled for t=31. Nothing is polled for the
second half of the deadline: the client is blind for as long as it spent
looking. The gap grows with the backoff, so the longer the discharge takes, the
longer it sits ready and uncollected.
That is most visible in the user-interactive flow, where the discharge only
exists once a person finishes a login at the third party and the client's whole
job in between is to notice when they do. A caller can work around it by
passing a capped
WithPollingBackoff, but the deadline is the real bound onhow long the client may wait, and nothing except the caller was consulting it.
Deriving the last wait from the deadline fixes the flow for every consumer,
whatever backoff they chose.
Details
boBeforeDeadlineis applied to the sleep, not to the backoff state, so theschedule keeps growing from its unclamped value and the clamp can only ever
shorten a single wait. It leaves a second of room before the deadline (or half
of what remains, when that is shorter) for the final request to complete, and
declines to clamp below 100ms so a nearly expired context expires rather than
turning into a spin on the third party. A context with no deadline is
unaffected.
Also drops the copy of
defaultBackoffinlined innextBO.NewClientalwaysassigns
pollBackoffNext, so that branch is unreachable and a change madethere does nothing, silently.
tp_test.gogains a poll case whose backoff outgrows the context after thefirst poll and whose discharge arrives in the window that used to be blind. It
fails with
context deadline exceededbefore this change.Related PRs