Retry with Exponential Backoff
Retrying a failed, idempotent operation with an increasing delay between attempts, to avoid hammering a struggling server.
Purpose
Retrying a failed request can recover from a transient failure, but retrying immediately and repeatedly can worsen an already-struggling server. Exponential backoff doubles (or otherwise increases) the delay between attempts, spacing retries out over time.
Example
async function fetchWithRetry(url, retries = 3, delayMs = 300) {
for (let attempt = 0; attempt <= retries; attempt++) {
try {
const response = await fetch(url);
if (response.ok) return response;
} catch {
// network error β fall through to retry
}
if (attempt < retries) {
await new Promise((resolve) => setTimeout(resolve, delayMs * 2 ** attempt));
}
}
throw new Error(`Failed after ${retries + 1} attempts.`);
}
Behavior notes
- Only retry an idempotent operation β one where repeating it has the same effect as doing it
once. A
GETis normally safe to retry; aPOSTthat creates or charges something is not, unless the server explicitly supports safe retry (an idempotency key, for instance). - Adding random βjitterβ to each delay (rather than a purely deterministic backoff) helps avoid many clients retrying in synchronized bursts after a shared outage.
- A maximum retry count and a maximum total delay both matter β unbounded retries can leave a user waiting indefinitely for an operation that will never succeed.
Common mistakes
- Retrying a non-idempotent operation (a payment, an account-creation request) without server-side protection against duplicate effects.
- Retrying immediately, repeatedly, with no backoff β can turn a brief server hiccup into a self-inflicted overload.
Runtime notes
A coding pattern built on core ECMAScript async features, behaving identically anywhere JavaScript runs.