JAVASCRIPT

Implement Exponential Backoff for Robust API Retries

Learn to build a robust retry mechanism for failed API requests using exponential backoff. This strategy improves resilience by waiting longer between retries, preventing server overload.

async function fetchWithRetryAndBackoff(url, options = {}, retries = 3, initialDelayMs = 1000) {
  let currentDelay = initialDelayMs;

  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      const response = await fetch(url, options);
      if (!response.ok) {
        // Consider specific status codes for retry (e.g., 429 Too Many Requests, 5xx Server Errors)
        // If it's a client error (4xx) other than 429, we might not want to retry.
        if (response.status >= 400 && response.status < 500 && response.status !== 429) {
          const errorData = await response.json().catch(() => ({ message: response.statusText }));
          throw new Error(`Client error: ${response.status} ${errorData.message}`);
        }
        throw new Error(`API error: ${response.status} ${response.statusText}`);
      }
      return await response.json();
    } catch (error) {
      console.warn(`Attempt ${attempt + 1}/${retries + 1} failed: ${error.message}`);
      if (attempt === retries) {
        console.error('Max retries reached. Giving up.');
        throw error;
      }
      // Exponential backoff with jitter (adding randomness to delay)
      const delayWithJitter = currentDelay + Math.random() * currentDelay;
      console.log(`Retrying in ${delayWithJitter.toFixed(0)}ms...`);
      await new Promise(resolve => setTimeout(resolve, delayWithJitter));
      currentDelay *= 2; // Exponential increase
    }
  }
}

// Example Usage:
// fetchWithRetryAndBackoff('/api/unreliable-service/data', { method: 'GET' }, 5, 500) // 5 retries, starting with 500ms delay
//   .then(data => console.log('Data fetched after retries:', data))
//   .catch(error => console.error('Failed to fetch data after all retries:', error));

// // Example for a POST request that might need idempotency if retried
// // (Combines with the Idempotency Key snippet)
// // const idempotencyKey = generateUUID(); // from Snippet 4
// // fetchWithRetryAndBackoff('/api/orders', {
// //   method: 'POST',
// //   headers: { 'Content-Type': 'application/json', 'Idempotency-Key': idempotencyKey },
// //   body: JSON.stringify({ item: 'product-x', quantity: 1 })
// // }, 3, 1000)
// // .then(data => console.log('Order processed:', data))
// // .catch(error => console.error('Order failed:', error));
How it works: This JavaScript snippet implements a robust retry mechanism for API requests using an exponential backoff strategy. When a `fetch` request fails (e.g., due to network issues, temporary server errors, or rate limits), the `fetchWithRetryAndBackoff` function automatically retries it after a progressively increasing delay. It includes "jitter" (randomness) in the delay to prevent all clients from retrying simultaneously. This pattern significantly enhances the resilience of client-side applications interacting with potentially unreliable APIs.

Need help integrating this into your project?

Our team of expert developers can help you build your custom application from scratch.

Hire DigitalCodeLabs