Backoff nghĩa là mỗi lần thử lại chờ lâu hơn theo cấp số nhân, cộng thêm jitter ngẫu nhiên để nhiều client không cùng bắn lại một thời điểm.
js
async function retry(fn, { retries = 3, base = 300 } = {}) {
for (let attempt = 0; ; attempt++) {
try {
return await fn()
} catch (err) {
if (attempt >= retries || !isRetryable(err)) throw err
const delay = base * 2 ** attempt * (0.5 + Math.random())
await new Promise((r) => setTimeout(r, delay))
}
}
}Chỉ retry khi an toàn:
- Lỗi mạng, timeout, 429, 503, 502 — tạm thời.
- Không retry 400, 401, 403, 422 — thử lại bao nhiêu lần cũng hỏng.
- Chỉ retry thao tác idempotent (GET, PUT, DELETE). Với POST tạo đơn hàng phải kèm idempotency key để server nhận ra lần thử lại và không tạo đơn thứ hai.
Các điểm thường bị hỏi thêm: tôn trọng header Retry-After nếu server trả về (dùng giá trị đó thay công thức); đặt trần số lần thử và trần delay để không treo UI; kèm AbortSignal để huỷ được cả chuỗi retry khi user rời trang.