Async retry dengan exponential backoff (vanilla JS)
Wrap async function dengan retry logic. Exponential backoff. Configurable max attempts, base delay, jitter. Zero dependencies.
Dipublikasikan 2 Juni 2026
Setiap kali fetch API external (payment gateway, social, AI), ada chance dia balas 5xx atau timeout. Bukan masalah app, masalah network/server lain. Retry dengan exponential backoff = self-healing tanpa user terganggu.
Kode
/**
* Retry async function dengan exponential backoff + jitter.
* @param {Function} fn - Async function to retry.
* @param {object} [opts]
* @param {number} [opts.maxAttempts=3] - Maximum total attempts.
* @param {number} [opts.baseDelay=300] - Delay first retry (ms).
* @param {number} [opts.maxDelay=10000] - Cap delay.
* @param {Function} [opts.shouldRetry] - Predicate (error) => bool.
* @returns {Promise<any>}
*/
async function retry(fn, opts = {}) {
const {
maxAttempts = 3,
baseDelay = 300,
maxDelay = 10000,
shouldRetry = (err) => true,
} = opts;
let attempt = 0;
let lastError;
while (attempt < maxAttempts) {
attempt++;
try {
return await fn(attempt);
} catch (err) {
lastError = err;
if (attempt >= maxAttempts || !shouldRetry(err)) {
throw err;
}
const delay = Math.min(maxDelay, baseDelay * Math.pow(2, attempt - 1));
const jitter = delay * 0.2 * Math.random();
const waitMs = delay + jitter;
console.warn(`[retry] attempt ${attempt} failed: ${err.message}. Retry in ${Math.round(waitMs)}ms`);
await new Promise((r) => setTimeout(r, waitMs));
}
}
throw lastError;
}
Pemakaian
// Retry HTTP request
const result = await retry(
async () => {
const res = await fetch('https://api.example.com/data');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
},
{
maxAttempts: 5,
baseDelay: 500,
shouldRetry: (err) => {
// Hanya retry untuk network error & 5xx
const msg = err.message;
return msg.includes('fetch') || msg.match(/HTTP 5\d\d/);
},
}
);
Kapan dipakai
- Fetch ke external API (payment gateway, social, weather)
- DB connection awal (saat app start, DB belum ready)
- Webhook delivery dari worker ke external
- File upload ke S3/R2 dengan timeout
Kapan JANGAN retry
- 400 Bad Request — kemungkinan body Anda salah, retry sama hasil
- 401 Unauthorized — token expired, butuh refresh dulu bukan retry
- 404 Not Found — resource gak ada
- 422 Unprocessable Entity — validation error
- Mutation idempotency tidak guaranteed — kalau POST tanpa idempotency key, retry bisa duplicate transaction
Atur shouldRetry predicate untuk filter case-case ini.
Catatan
- Jitter (random 20% tambahan) penting untuk avoid thundering herd kalau banyak client retry bersamaan
- Max delay cap prevent waiting too long (jangan tunggu 5 menit)
- Console warn helpful saat debug; di production switch ke proper logger
Untuk production-grade: pakai library seperti
p-retryatauaxios-retryyang sudah handle edge case. Snippet ini untuk understanding atau minimal-dep usage.
# tags
retryasyncresiliencebackoff
Ditulis oleh Asti Larasati · 2 Juni 2026