Skip to content

Size each discharge pass's timeout for what it waits on - #5124

Merged
dangra merged 1 commit into
masterfrom
discharge-poll-deadline
Aug 25, 2026
Merged

Size each discharge pass's timeout for what it waits on#5124
dangra merged 1 commit into
masterfrom
discharge-poll-deadline

Conversation

@dangra

@dangra dangra commented Aug 25, 2026

Copy link
Copy Markdown
Member

refreshDischargeTokens makes up to two passes over the undischarged tickets and each one builds its own context from fly-go's default, so a single command can spend twice that budget. This gives the two passes separate timeouts, sized for the kind of wait each one actually does: 30 seconds for the pass that can only talk to servers, 90 for the pass that waits on a person.

Context

The first pass runs without a UserURLCallback, which is what makes the macaroon client fetch every ticket in parallel. A third party that wants the user cannot be satisfied there and fails immediately, so everything that pass can still accomplish is a server round trip. It was holding the same 90 second budget as the interactive retry, which nothing in it can use.

The retry is where the cost is: the browser opens, the user works through their identity provider, and the client polls until the discharge appears. That is the wait 90 seconds was chosen for in superfly/fly-go#286.

Consequences of splitting them:

  • the worst case a user can observe drops from about three minutes to about two.
  • the agent (agent/server/server.go) passes uucb = nil and so only ever runs the non-interactive pass. It stops reserving a 90 second budget it can never spend.
  • a genuinely slow non-interactive discharge now has 30 seconds rather than 90. That is the same budget this path had before v0.4.89, and it is not the case the longer default was raised for.

Details

The timeouts move behind doRefreshDischargeTokens, following the fetchOrgTokens / doFetchOrgTokens seam already in this file, so the split can be tested in a couple of seconds instead of on the real durations. The tests drive a third party that never discharges and assert each pass stops at its own budget; each one fails if the other pass's timeout is wired in.

refreshDischargeTokens makes up to two passes and each one built its own
context from fly-go's default, so a command could spend twice that
budget: 90 seconds waiting for servers, then 90 more waiting for a
person. The two passes are not the same kind of wait, and now that
fly-go takes WithDischargeTimeout they don't have to share a number.

The pass without a UserURLCallback cannot wait on anyone. A third party
that wants the user fails it immediately, so everything left is a server
round trip; it gets 30 seconds. The retry that can open a browser keeps
the 90 seconds, which is what an interactive login through an identity
provider is sized for. Worst case goes from three minutes to two, and
the agent, which never has a callback, stops holding a 90 second budget
it can never use.

Timeouts move behind doRefreshDischargeTokens so the split is testable
without waiting on the real ones.
Copilot AI lite review requested due to automatic review settings August 25, 2026 00:19

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@dangra
dangra merged commit 721aee9 into master Aug 25, 2026
56 of 59 checks passed
@dangra
dangra deleted the discharge-poll-deadline branch August 25, 2026 01:56
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.

2 participants