How to retry a failed operation
Short answer
Call the function in a loop. If it succeeds, return the result; if it fails, try again, and after the last attempt pass the error on:
async function retry(task, attempts = 3) {
for (let i = 1; i <= attempts; i++) {
try {
return await task();
} catch (error) {
console.log(`attempt ${i} failed: ${error.message}`);
if (i === attempts) throw error;
}
}
}
let calls = 0;
const unstable = async () => {
calls++;
if (calls < 3) throw new Error('server busy');
return 'data';
};
console.log(await retry(unstable));Output:
attempt 1 failed: server busy
attempt 2 failed: server busy
dataA growing pause
Do not retry immediately: wait longer after each failure. This is called exponential backoff, and it gives the server time to recover:
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function retry(task, attempts = 4, delay = 100) {
for (let i = 0; i < attempts; i++) {
try {
return await task();
} catch (error) {
if (i === attempts - 1) throw error;
const wait = delay * 2 ** i;
console.log(`waiting ${wait} ms`);
await sleep(wait);
}
}
}
let calls = 0;
const result = await retry(async () => {
if (++calls < 4) throw new Error('timeout');
return 'ok';
});
console.log(result);Output:
waiting 100 ms
waiting 200 ms
waiting 400 ms
okWith fetch
Retry only temporary failures: network errors and statuses 500 and above. A 404 will not get better after a pause:
const response = await retry(async () => {
const res = await fetch('/api/orders');
if (res.status >= 500) throw new Error(`Server error ${res.status}`);
return res;
});Common mistake
Without the await in return await task(), the error of the promise is not caught inside try, and the retry never happens:
async function retryBroken(task) {
for (let i = 1; i <= 3; i++) {
try {
return task();
} catch {
console.log('retrying');
}
}
}
try {
await retryBroken(async () => {
throw new Error('failed');
});
} catch (error) {
console.log('no retries:', error.message);
}Output:
no retries: failedFunctions used in this recipe
- Promise — A promise of a result that will be ready later: success or failure.
- async function — A function that always returns a promise and lets you use await inside.
- try...catch — Catches errors so the program does not stop.