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?
You will practise
- 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
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
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
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);Related questions
Source: AI & Agents — practice tasks — An exercise written for the study programme, not a confirmed interview task.