← All tasksJavaScript · Senior

retry: retry on failure

Write a function retry(fn, attempts, delay). It calls fn (a function that returns a promise or throws) and on failure tries again, up to attempts times in total, waiting delay milliseconds between attempts.

Return the result of the first successful attempt. If every attempt fails, reject with the error from the last one. A synchronous throw inside fn also counts as a failed attempt.

Tests (5)

  1. const f = fn(async () => 'ok');
    expect(await retry(f, 3, 10)).toBe('ok');
    expect(f).toHaveBeenCalledTimes(1);
  2. let n = 0;
    const f = fn(async () => { n++; if (n < 3) throw new Error('fail ' + n); return n; });
    expect(await retry(f, 5, 10)).toBe(3);
    expect(f).toHaveBeenCalledTimes(3);
  3. const f = fn(async () => { throw new Error('nope ' + f.calls.length); });
    await expect(retry(f, 3, 5)).rejects.toThrow('nope 3');
    expect(f).toHaveBeenCalledTimes(3);
  4. const f = fn(() => { throw new Error('sync'); });
    await expect(retry(f, 2, 5)).rejects.toThrow('sync');
    expect(f).toHaveBeenCalledTimes(2);
  5. let n = 0;
    const f = async () => { n++; if (n === 1) throw new Error('x'); return 'done'; };
    const started = Date.now();
    expect(await retry(f, 2, 60)).toBe('done');
    expect(Date.now() - started >= 50).toBe(true);