w3resource

Implementing Chained retries with increasing Delays in JavaScript


Chained Retry with Delays:

Write a JavaScript program to implement a function that retries a failed asynchronous operation with increasing delays between attempts.

Solution-1: Using async/await and setTimeout

Code:

async function retryWithDelay(asyncFunction, retries, delay) {
  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      // Try executing the asynchronous function
      return await asyncFunction();
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error.message);

      if (attempt === retries) {
        throw new Error('All retries failed'); // Throw error after all retries fail
      }

      // Wait for the specified delay before retrying
      await new Promise((resolve) => setTimeout(resolve, delay * attempt));
    }
  }
}

// Example usage of retryWithDelay
const simulateAsyncTask = async () => {
  if (Math.random() > 0.7) {
    return 'Success!';
  } else {
    throw new Error('Random failure');
  }
};

retryWithDelay(simulateAsyncTask, 5, 1000)
  .then((result) => console.log('Operation succeeded:', result))
  .catch((error) => console.error('Operation failed:', error.message));

Output:

"Attempt 1 failed:"
"Operation succeeded:"
Undefined

Explanation:

  • 'asyncFunction' is executed inside a `try` block to handle potential errors.
  • On failure, a delay is introduced using `setTimeout` before retrying.
  • The delay increases with each retry (linear backoff).

Solution-2: Exponential Backoff

Code:

// Simulated asynchronous task that randomly succeeds or fails
async function simulateAsyncTask() {
  // Randomly decide success or failure
  if (Math.random() > 0.7) {
    return "Success!";
  } else {
    throw new Error("Random failure");
  }
}

// Function to retry an async operation with exponential backoff
async function retryWithExponentialBackoff(asyncFunction, retries, initialDelay) {
  let delay = initialDelay; // Start with the initial delay

  for (let attempt = 1; attempt <= retries; attempt++) {
    try {
      // Try executing the asynchronous function
      return await asyncFunction();
    } catch (error) {
      console.error(`Attempt ${attempt} failed:`, error.message);

      if (attempt === retries) {
        throw new Error("All retries failed"); // Throw error after all retries fail
      }

      // Wait for the current delay before retrying
      await new Promise((resolve) => setTimeout(resolve, delay));
      delay *= 2; // Double the delay for exponential backoff
    }
  }
}

// Example usage of retryWithExponentialBackoff
retryWithExponentialBackoff(simulateAsyncTask, 5, 500)
  .then((result) => console.log("Operation succeeded:", result))
  .catch((error) => console.error("Operation failed:", error.message));

Output:

"Attempt 1 failed:"
"Operation succeeded:"
undefined

Explanation:

  • Starts with an initial delay and doubles it after each failure (exponential backoff).
  • Delays grow progressively to reduce the load on resources during retries.
  • Retries stop once the maximum number of attempts is reached or the operation succeeds.

Key Differences:

  • Solution 1 uses a linear backoff, increasing delay by a fixed amount.
  • Solution 2 employs exponential backoff, doubling the delay each time.

See the Pen promises-and-async-await-exercise-20 by w3resource (@w3resource) on CodePen.


Improve this sample solution and post your code through Disqus

Previous: Optimize API Fetching: Parallel vs Sequential Methods Explained.

What is the difficulty level of this exercise?

Test your Programming skills with w3resource's quiz.



Follow us on Facebook and Twitter for latest update.