Weather Station Retries

EasysimulationAlso known as Exponential Backoff with a Cap

Two hundred weather stations on a hillside upload a reading every few minutes. When the upload server restarts, every station fails at once. If each one retries every 100 ms, the server comes back to a wall of retries and falls over again. So each station waits longer after every failure: 100 ms, then 200, then 400, doubling up to a ceiling. A reading is useless after a while, so a station also gives up when its total waiting would pass a time budget.

Every client that calls a network service needs this schedule (see Idempotency and Retries and Reliability and Failure). Real clients also add random jitter, for example picking a random wait between 0 and the scheduled value, so stations do not retry in lockstep. Here you compute the schedule that the jitter draws from.

Your task

Write retryDelays(baseMs, capMs, maxRetries, budgetMs). Return the list of waits, in milliseconds, before retry 1, retry 2, and so on.

  • The wait before retry k (counting from 1) is min(capMs, baseMs × 2k−1).
  • There are at most maxRetries retries.
  • Stop before any retry whose wait would make the total of all waits so far greater than budgetMs. A total exactly equal to the budget is allowed.

Return an empty list if no retry fits.

retryDelays(baseMs: int, capMs: int, maxRetries: int, budgetMs: int) → int[]

Examples

Example 1
Input
baseMs = 100
capMs = 1000
maxRetries = 6
budgetMs = 10000
Output
[100, 200, 400, 800, 1000, 1000]
Why

The waits double from 100: 100, 200, 400, 800. The next would be 1,600, but the cap is 1,000, so retries 5 and 6 wait 1,000 each. The total is 3,500 ms, well inside the 10,000 ms budget, so all 6 retries happen.

Example 2
Input
baseMs = 500
capMs = 4000
maxRetries = 10
budgetMs = 6000
Output
[500, 1000, 2000]
Why

After three retries the station has waited 500 + 1,000 + 2,000 = 3,500 ms. Retry 4 would wait 4,000 ms more, for a total of 7,500, which is over the 6,000 ms budget, so the station gives up there. It does not look for a later, shorter wait: waits never shrink.

Constraints

  • 1 ≤ baseMs ≤ capMs ≤ 3,600,000
  • 0 ≤ maxRetries ≤ 60
  • 0 ≤ budgetMs ≤ 1,000,000,000
Start with brute force

A first version computes baseMs × 2k−1 with a power function for every retry and then applies the cap. JavaScript and Python give the right answer, but the number in the middle is huge: for retry 60 with a base of 1,000 ms it is about 5.8 × 1020 ms. In a language with 64-bit integers that overflows (the limit is about 9.2 × 1018) and can come out negative, and a negative wait means retrying instantly, in a tight loop, which is the exact storm backoff exists to prevent.

Doubling a value that is already capped never leaves the range of the constraints, so it avoids the problem with no extra work.

Hints

0 of 4 shown

Walkthrough and solution

Unlocks when you pass every test. Stuck for a while? Looking is fine too, as long as you then close it and write the code yourself.

Ctrl+Enter runs

Run your code to see results here. Run checks the examples. Submit checks every test, including hidden edge cases.

Write code