In other programming languages such as Java, Ruby and Python, there are Thread.sleep(), sleep, and time.sleep() methods to pause the execution of the current thread and wait after specified time to continue the execution, and when used together with loops, it can help address race condition issues for example. In node.js, and generally JavaScript, the way to pause and wait may not seem very obvious and frequently seen due to the nature of single-threaded, event-driven, and asyncronous architecture. However, since the use of wait and retry is still needed and helpful under certain circumstances, it is possible to simulate similar functions and effects in nodejs or JavaScript.

How to simulate sleep/wait with setTimeout

  • with new Promise
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
  • with util.promisify
import util from 'node:util';

const wait = util.promisify(setTimeout);

How to implement retry with back-off

  • with recursive functions
const retry = async (fn, depth = 0, numRetries = 3) => {
  try {
    return await fn();
  } catch (e) {
    if (depth === numRetries) {
      throw e;
    }
    console.log('retry...');
    await wait(2 ** depth * 10);
  
    return retry(fn, depth + 1, numRetries);
  }
}
  • with for loops
const retry = async (fn, retryDelayMs = 100, numRetries = 3) => {
  for (let attempt = 0; attempt <= numRetries; attempt++) {
    try {
      return await fn();
    } catch (e) {
      if (attempt === numRetries) {
        throw e;
      }
      console.log('retry...');
      await wait(retryDelayMs);

      retryDelayMs *= 2;
    }
  }
}
  • until function returns truthy value
const retry = async (fn, retryDelayMs = 100, numRetries = 3) => {
  let result;
  for(let i = 0; i < numRetries; i++) {
    try {
      result = await fn();
    } catch (e) {
      // ignore errors
    }
    if(result) {
      return result;
    }
    console.log('retry...');
    await wait(retryDelayMs);

    retryDelayMs *= 2;
  }
  return result;
};

References

Post tagged with: nodejs