Skip to content
Jobless Busters
Runs testsIntermediate15–25 min

Sensible request retries

Task: after a 429 or a selected server error, try again, but with a pause and a limit on attempts. Don't retry a 403. Respect the time given by the server and the possibility of cancellation.

Tests: classifying errors and making time testable.

Contract from the reference tests: retry(operation, options), where options has attempts and optionally baseMs (default 100), capMs (5000), signal, random and sleep(ms, signal). Transient statuses are 429, 500, 502, 503 and 504 from the HttpError class (available alongside). The pause is a random fraction of min(capMs, baseMs * 2 ** n), but no shorter than retryAfterMs. Cancellation is not a transient error.

The Retry-After time is already converted to milliseconds; parsing a date is an extension.

Follow-up: what if the write succeeded but the response never arrived?

  • Tell a temporary error from a permanent one
  • Growing pauses with randomness (jitter)
  • Respect Retry-After
  • Test timing through an injected sleep function
The 3 tests

Tests ported from the source material's reference.test.ts (node:test). In the browser they run with the same set of assertions.

retry: Retry-After, jitter and success

JavaScript
let calls = 0; const delays = [];
const value = await retry(async () => { if (++calls < 3) throw new HttpError(429, 200); return 7; },
  { attempts: 3, baseMs: 100, random: () => 0.5, sleep: async ms => { delays.push(ms); } });
assert.equal(value, 7);
assert.deepEqual(delays, [200, 200]);

retry: no retry on 403, and the attempt limit

JavaScript
let calls = 0;
await assert.rejects(retry(async () => { calls++; throw new HttpError(403); }, { attempts: 4 }));
assert.equal(calls, 1);
calls = 0;
await assert.rejects(retry(async () => { calls++; throw new HttpError(503); }, { attempts: 2, sleep: async () => {} }));
assert.equal(calls, 2);

retry: cancellation isn't a transient error

JavaScript
const c = new AbortController(); c.abort(new Error('stop')); let calls = 0;
await assert.rejects(retry(async () => { calls++; return 1; }, { attempts: 3, signal: c.signal }), /stop/);
assert.equal(calls, 0);

Source: AI & Agents — practice tasks — An exercise written for the study programme, not a confirmed interview task.

JavaScript · runs in a Web Worker in your browser

Provided helpers (already defined, read-only)

Tab indents · Esc, then Tab, leaves the editor · ⌘/Ctrl + Enter runs the tests · Your code is saved in this browser.

Run the tests to check your solution. 3 predefined tests.

Stuck? Hints go from gentle to specific.

Give it a real try first — the solution is most useful after you've struggled a bit.