fix: convert backoff delay to seconds when retrying - #962
frederico-kluser wants to merge 1 commit into
Conversation
`withRetries` tracks its backoff in milliseconds, as both `INITIAL_DELAY` and `TWENTY_MINUTES` state in their comments, but passed that value to `sleep`, which takes seconds. Every backoff wait was therefore 1000x longer than intended: the second retry waited 100 seconds instead of the documented 100 ms, and the ceiling became about 13.9 days. That `sleep` takes seconds is confirmed by the 429 branch a few lines above, which passes the Bot API's `retry_after` to it directly, and by the polling loop, which passes `sleepSeconds`. So the conversion belongs at this call site. The failure mode was quiet: during the wait the process stays alive, `start()` has neither resolved nor rejected, and the retry error only reaches `debugErr`, which is silent without `DEBUG`. A transient network blip at startup cost at least 100 seconds of silence. The existing retry tests assert an initial attempt plus one retry, and the first retry is deliberately immediate, so no `sleep` was ever reached by the suite. The new test drives a second retry under a fake clock and fails without this change. Also aligns the docstring with the named constant: the ceiling is 20 minutes, where the text said 1 hour. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Is there any reason to create this PR when #960 already exist? To be clear, I'm not saying that we shouldn't have multiple PRs that attempt to solve the same issue. But I would expect them to be at least qualitatively different in the approach they take - at least, to the extent that simply leaving a comment for discussion in the existing PR is insufficient. |
|
Closing this as a duplicate of #960, which proposes the same fix and was opened three days earlier. I missed it before opening this — my search covered issues but not pull requests, which is entirely on me. Apologies for the noise. @roshnicdave got there first and their PR should be the one that lands. I have left the two small points that this PR carried in a comment on #960, and #961 stays open with a runnable reproduction and the impact analysis, in case that is useful when reviewing. |
Fixes #961.
The bug
withRetriestracks its backoff in milliseconds — bothINITIAL_DELAYandTWENTY_MINUTESsay// ms— but passed that value tosleep, which takes seconds. Every backoff wait was 1000× longer than intended: the second retry waited 100 seconds instead of the documented 100 ms, and the ceiling became roughly 13.9 days instead of the documented hour.That
sleepreally does take seconds is settled by its neighbours: the 429 branch a few lines above passes the Bot API'sretry_afterto it directly, and the polling loop passessleepSeconds. Both are correct, so the conversion belongs at this one call site rather than insleep.The change
if (lastDelay !== INITIAL_DELAY) { - await sleep(lastDelay, signal); + // `sleep` expects seconds, but the backoff is tracked in + // milliseconds, so it has to be converted here + await sleep(lastDelay / 1000, signal); }Plus a regression test, and one docstring line.
Why it went unnoticed
The two existing retry tests assert
callCount === 2— the initial attempt plus the first retry. The first retry is deliberately immediate, sinceif (lastDelay !== INITIAL_DELAY)is false on the first pass, so the suite never reachedsleepat all. The delay only appears on the second retry.The new test drives a second retry under
FakeTimeand advances the clock by exactly 100 ms. It fails onmain(AssertionError: Values are not equal, in 20 ms — it does not hang) and passes with this change.A question for you
Once the units are fixed, the ceiling is 20 minutes, matching the named constant, while the docstring said "1 hour". I assumed the constant is authoritative and aligned the prose to it. If an hour was the intent, then
TWENTY_MINUTESshould change instead and I am happy to switch it — just say which.Checks
deno task devpasses on this branch:deno fmt(59 files),deno lint(45 files),deno task test(39 passed, 449 steps, 0 failed),deno task check.deno fmtleft everything but the two edited files untouched.Reproduction script and measured output are in #961.