Navigation

Node.js

How to Retry Failed HTTP Requests

Automatically retry failed HTTP requests in Node.js with exponential backoff. Handle network errors and temporary failures gracefully.

Table Of Contents

Problem

Your HTTP requests occasionally fail due to network issues or temporary server problems, and you need to retry them automatically before giving up.

Solution

// Basic retry with exponential backoff
async function retryRequest(url, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url);
      
      if (response.ok) {
        return await response.json();
      }
      
      throw new Error(`HTTP ${response.status}`);
    } catch (error) {
      console.log(`Attempt ${attempt} failed: ${error.message}`);
      
      if (attempt === maxRetries) {
        throw error;
      }
      
      // Exponential backoff: 1s, 2s, 4s
      const delay = Math.pow(2, attempt - 1) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Retry with condition
async function retryWithCondition(url, options = {}) {
  const { maxRetries = 3, shouldRetry = (error) => true } = options;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url);
      
      if (response.ok) {
        return await response.json();
      }
      
      const error = new Error(`HTTP ${response.status}`);
      error.status = response.status;
      
      // Don't retry client errors (4xx)
      if (response.status >= 400 && response.status < 500) {
        throw error;
      }
      
      throw error;
    } catch (error) {
      if (attempt === maxRetries || !shouldRetry(error)) {
        throw error;
      }
      
      const delay = 1000 * attempt;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
}

// Retry wrapper function
function withRetry(fn, maxRetries = 3) {
  return async (...args) => {
    let lastError;
    
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await fn(...args);
      } catch (error) {
        lastError = error;
        
        if (attempt < maxRetries) {
          const delay = Math.pow(2, attempt - 1) * 1000;
          await new Promise(resolve => setTimeout(resolve, delay));
        }
      }
    }
    
    throw lastError;
  };
}

// Usage
const reliableFetch = withRetry(fetch, 3);

Explanation

Wrap requests in a loop that catches errors and waits before retrying. Use exponential backoff (1s, 2s, 4s) to avoid overwhelming the server.

Don't retry client errors (4xx status codes) as they indicate request problems, not temporary failures. Only retry server errors (5xx) and network errors.

Share this article

Add Comment

No comments yet. Be the first to comment!

More from Node.js