Skip to content

Add totalTimeout option and make timeout be per retry#848

Merged
sindresorhus merged 6 commits intomainfrom
resettimeout
Mar 26, 2026
Merged

Add totalTimeout option and make timeout be per retry#848
sindresorhus merged 6 commits intomainfrom
resettimeout

Conversation

@sindresorhus
Copy link
Copy Markdown
Owner

Fixes #497

@sindresorhus sindresorhus requested a review from sholladay March 25, 2026 20:59
@sindresorhus
Copy link
Copy Markdown
Owner Author

In aac83fa, I changed Ky to make timeout apply to the whole operation. However, doing some research now, I realize most HTTP clients across languages treat timeout as per-attempt by default:

  • got (JS): timeout.request is per-attempt
  • reqwest (Rust): timeout() is per-attempt
  • httpx (Python): timeout is per-attempt
  • requests (Python): timeout is per-attempt
  • Guzzle (PHP): timeout is per-attempt

The only exception is axios-retry, which defaults to total (with a shouldResetTimeout opt-in).

So, I'm wondering whether we should make retry.resetTimeout true by default.

Thoughts?

@sholladay
Copy link
Copy Markdown
Collaborator

The most intuitive model to me is where I provide the numRetries and the timeout for each attempt, and the total timeout of the operation is just the natural product of those inputs. So, basically what those other libraries are doing and resetTimeout = true.

That said, I think it's perfectly valid to want to also timeout the whole operation. The current behavior seems kind of backwards to me, though. It says, "By default, timeout is a total timeout across all retries, meaning later retries get progressively less time." If I were writing retry logic by hand, I would give successive retries equal or more time, not less.

@sindresorhus
Copy link
Copy Markdown
Owner Author

I found a better approach. totalTimeout option. With the new design, timeout just works the way everyone expects. If you also need a total cap, you opt into it explicitly with totalTimeout.

@sindresorhus sindresorhus changed the title Add retry.resetTimeout option to reset timeout budget on each retry Add totalTimeout option Mar 26, 2026
@sindresorhus sindresorhus changed the title Add totalTimeout option Add totalTimeout option and make timeout be per retry Mar 26, 2026
@sholladay
Copy link
Copy Markdown
Collaborator

I think it's pretty good but the difference between the timeout options is a little unclear at first glance. Maybe we should rename them?

  • timeout -> attemptTimeout or retryTimeout (or retry.timeout)
  • totalTimeout -> timeout

@sindresorhus
Copy link
Copy Markdown
Owner Author

Every major HTTP client uses plain timeout to mean per-request. So I think that's what people expect of a timeout option. totalTimeout is just a nice added bonus feature.

@sindresorhus
Copy link
Copy Markdown
Owner Author

I have tried to make the docs clearer though.

Make `timeout` per-attempt by default, matching how every major HTTP client works. Each retry now gets the full timeout value.
@sindresorhus sindresorhus merged commit c20d7c7 into main Mar 26, 2026
6 checks passed
@sindresorhus sindresorhus deleted the resettimeout branch March 26, 2026 17:13
Repository owner deleted a comment from xpirt Mar 27, 2026
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.

Allow to specify timeout for single request in additional for total timeout including retries

2 participants