DEV Community

Young Gao
Young Gao

Posted on

Retry Patterns That Work: Exponential Backoff, Jitter, and Dead Letter Queues (2026)

Network call fails. You retry immediately. It fails again. You retry in a tight loop. You DDoS your own service.

Exponential Backoff

Wait longer between each retry: 1s, 2s, 4s, 8s, 16s.

async function retry<T>(fn: () => Promise<T>, maxRetries = 5): Promise<T> {
  for (let i = 0; i < maxRetries; i++) {
    try { return await fn(); }
    catch (err) {
      if (i === maxRetries - 1) throw err;
      const delay = Math.min(1000 * Math.pow(2, i), 30000);
      const jitter = delay * (0.5 + Math.random() * 0.5);
      await new Promise(r => setTimeout(r, jitter));
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Why Jitter Matters

Without jitter, 1000 clients all retry at the same exponential intervals. They stampede the server simultaneously. Jitter randomizes the retry time so clients spread out naturally.

What NOT to Retry

Retry: 429 (rate limit), 503 (overloaded), timeout, connection refused.
Do NOT retry: 400 (bad request), 401 (unauthorized), 404 (not found), 422 (validation error). These will always fail.

Dead Letter Queue

After max retries exhausted, put the failed message in a DLQ. Review and reprocess later. Never silently drop messages.


Part of my Production Backend Patterns series. Follow for more practical backend engineering.


If this was useful, consider:


You Might Also Like

Follow me for more production-ready backend content!


If this helped you, buy me a coffee on Ko-fi!

Top comments (0)