Convert Figma logo to code with AI

tim-kos logonode-retry

Abstraction for exponential and custom retry strategies for failed operations.

1,258
86
1,258
21

Top Related Projects

14,921

🌐 Human-friendly and powerful HTTP request library for Node.js

Ajax for Node.js and browsers (JS HTTP client). Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.

109,037

Promise based HTTP client for the browser and node.js

25,538

🏊🏾 Simplified HTTP request client.

Quick Overview

Node-retry is a lightweight and flexible retry utility for Node.js applications. It allows developers to easily implement retry logic for operations that may fail temporarily, such as network requests or database queries, improving the robustness and reliability of their applications.

Pros

  • Simple and intuitive API for implementing retry logic
  • Highly configurable with options for retry attempts, delays, and backoff strategies
  • Supports both callback and promise-based approaches
  • Lightweight with no external dependencies

Cons

  • Limited built-in retry strategies compared to some more comprehensive libraries
  • Lacks advanced features like circuit breakers or bulkhead patterns
  • Documentation could be more extensive, especially for advanced use cases
  • No built-in support for distributed systems or cluster-aware retries

Code Examples

  1. Basic retry with default options:
const retry = require('retry');

function fetchData(callback) {
  const operation = retry.operation();
  
  operation.attempt((currentAttempt) => {
    // Simulating an API call that might fail
    someApiCall((err, result) => {
      if (operation.retry(err)) {
        return;
      }
      callback(err ? operation.mainError() : null, result);
    });
  });
}
  1. Retry with custom options:
const retry = require('retry');

const operation = retry.operation({
  retries: 5,
  factor: 2,
  minTimeout: 1000,
  maxTimeout: 60000,
  randomize: true
});

operation.attempt((currentAttempt) => {
  // Your operation logic here
  if (shouldRetry) {
    operation.retry(new Error('Temporary failure'));
  } else {
    // Success or permanent failure
  }
});
  1. Using promises with async/await:
const retry = require('retry');
const { promisify } = require('util');

const retryOperation = promisify(retry.operation);

async function fetchWithRetry() {
  try {
    await retryOperation({
      retries: 3,
      factor: 2,
      minTimeout: 1000,
    }, async (bail) => {
      const response = await fetch('https://api.example.com/data');
      if (!response.ok) {
        bail(new Error('Request failed'));
      }
      return response.json();
    });
  } catch (error) {
    console.error('All retries failed:', error);
  }
}

Getting Started

To use node-retry in your project, follow these steps:

  1. Install the package:

    npm install retry
    
  2. Import and use in your code:

    const retry = require('retry');
    
    const operation = retry.operation({
      retries: 3,
      factor: 2,
      minTimeout: 1000,
    });
    
    operation.attempt((currentAttempt) => {
      // Your operation logic here
      if (shouldRetry) {
        operation.retry(new Error('Temporary failure'));
      } else {
        // Success or permanent failure
      }
    });
    

This setup provides a basic retry mechanism with 3 attempts, exponential backoff, and a minimum timeout of 1 second between retries.

Competitor Comparisons

14,921

🌐 Human-friendly and powerful HTTP request library for Node.js

Pros of got

  • More comprehensive HTTP client with built-in retries, redirects, and other features
  • Actively maintained with frequent updates and a large community
  • Supports both Promise and stream-based APIs for flexible usage

Cons of got

  • Larger package size and more dependencies
  • Steeper learning curve due to more features and options
  • May be overkill for simple retry scenarios

Code comparison

node-retry:

var retry = require('retry');

var operation = retry.operation({
  retries: 5,
  factor: 3,
  minTimeout: 1 * 1000,
  maxTimeout: 60 * 1000,
  randomize: true,
});

operation.attempt(function(currentAttempt) {
  // ... perform operation
});

got:

const got = require('got');

(async () => {
  try {
    const response = await got('https://api.example.com', {
      retry: {
        limit: 5,
        calculateDelay: ({attemptCount}) => attemptCount * 1000,
      },
    });
    console.log(response.body);
  } catch (error) {
    console.error(error);
  }
})();

Summary

node-retry is a lightweight, focused library for implementing retry logic, while got is a full-featured HTTP client with built-in retry capabilities. node-retry offers more control over retry behavior but requires manual integration with HTTP requests. got provides a more convenient, all-in-one solution for HTTP requests with retries, but may be excessive for simple use cases.

Ajax for Node.js and browsers (JS HTTP client). Maintained for @forwardemail, @ladjs, @spamscanner, @breejs, @cabinjs, and @lassjs.

Pros of superagent

  • More comprehensive HTTP client library with advanced features
  • Supports both Node.js and browser environments
  • Extensive plugin ecosystem for additional functionality

Cons of superagent

  • Larger package size and potentially more complex for simple retry scenarios
  • May have a steeper learning curve for basic use cases

Code Comparison

node-retry:

var retry = require('retry');

var operation = retry.operation({
  retries: 5,
  factor: 3,
  minTimeout: 1 * 1000,
  maxTimeout: 60 * 1000,
  randomize: true,
});

operation.attempt(function(currentAttempt) {
  // ... perform operation
});

superagent:

const superagent = require('superagent');

superagent
  .get('https://api.example.com/data')
  .retry(5)
  .end((err, res) => {
    // ... handle response
  });

Key Differences

  • node-retry focuses specifically on retry logic, while superagent is a full-featured HTTP client
  • superagent provides built-in HTTP functionality, whereas node-retry requires additional HTTP libraries
  • node-retry offers more granular control over retry behavior, including custom backoff strategies
  • superagent's retry mechanism is more straightforward for simple HTTP requests but may be less flexible for complex retry scenarios

Use Cases

  • Choose node-retry for fine-grained control over retry logic in various contexts
  • Opt for superagent when building applications that require a robust HTTP client with built-in retry functionality
109,037

Promise based HTTP client for the browser and node.js

Pros of axios

  • Comprehensive HTTP client with support for multiple request methods
  • Built-in request and response interceptors for easy manipulation
  • Automatic request and response transformations (e.g., JSON parsing)

Cons of axios

  • Larger package size and more dependencies
  • Potentially overkill for simple retry functionality
  • Steeper learning curve for basic use cases

Code comparison

axios:

axios.get('https://api.example.com/data')
  .then(response => console.log(response.data))
  .catch(error => console.error(error));

node-retry:

retry(function(attempt) {
  // Attempt to make a request
}, {retries: 3})
.then(function(result) {
  console.log(result);
});

Key differences

  • axios is a full-featured HTTP client, while node-retry focuses solely on retry functionality
  • node-retry provides more granular control over retry behavior
  • axios offers built-in support for various HTTP methods and request configurations
  • node-retry is more lightweight and specialized for retry operations

Use cases

  • Choose axios for comprehensive HTTP request handling and advanced features
  • Opt for node-retry when you need specific retry logic without additional HTTP client functionality

Community and maintenance

  • axios has a larger community and more frequent updates
  • node-retry is more focused and stable, with less frequent updates
25,538

🏊🏾 Simplified HTTP request client.

Pros of request

  • More comprehensive HTTP client with support for various methods and options
  • Extensive documentation and large community support
  • Built-in features like automatic redirects, cookies, and authentication

Cons of request

  • Larger package size and more dependencies
  • Steeper learning curve for simple use cases
  • No longer actively maintained (deprecated)

Code comparison

request:

const request = require('request');

request('https://api.example.com', (error, response, body) => {
  if (!error && response.statusCode == 200) {
    console.log(body);
  }
});

node-retry:

const retry = require('retry');

const operation = retry.operation();

operation.attempt((currentAttempt) => {
  // Your code here
  if (shouldRetry) {
    operation.retry(err);
  }
});

Key differences

  • node-retry focuses solely on retry logic, while request is a full-featured HTTP client
  • request handles HTTP requests out of the box, while node-retry requires additional implementation for network operations
  • node-retry provides more granular control over retry behavior, including customizable backoff strategies
  • request offers a simpler API for basic HTTP requests, while node-retry requires more setup for similar functionality

Use cases

  • Use request for general-purpose HTTP client needs (though consider alternatives due to its deprecated status)
  • Choose node-retry when you need fine-grained control over retry logic in various scenarios, not limited to HTTP requests

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

Build Status codecov

retry

Abstraction for exponential and custom retry strategies for failed operations.

Installation

npm install retry

Current Status

This module has been tested and is ready to be used.

Tutorial

The example below will retry a potentially failing dns.resolve operation 10 times using an exponential backoff strategy. With the default settings, this means the last attempt is made after 17 minutes and 3 seconds.

var dns = require('dns');
var retry = require('retry');

function faultTolerantResolve(address, cb) {
  var operation = retry.operation();

  operation.attempt(function(currentAttempt) {
    dns.resolve(address, function(err, addresses) {
      if (operation.retry(err)) {
        return;
      }

      cb(err ? operation.mainError() : null, addresses);
    });
  });
}

faultTolerantResolve('nodejs.org', function(err, addresses) {
  console.log(err, addresses);
});

Of course you can also configure the factors that go into the exponential backoff. See the API documentation below for all available settings. currentAttempt is an int representing the number of attempts so far.

var operation = retry.operation({
  retries: 5,
  factor: 3,
  minTimeout: 1 * 1000,
  maxTimeout: 60 * 1000,
  randomize: true,
});

Example with promises

const retry = require('retry')
const delay = require('delay')

const isItGood = [false, false, true]
let numAttempt = 0

function retryer() {
  let operation = retry.operation()

  return new Promise((resolve, reject) => {
    operation.attempt(async currentAttempt => {
      console.log('Attempt #:', numAttempt)
      await delay(2000)

      const err = !isItGood[numAttempt] ? true : null
      if (operation.retry(err)) {
        numAttempt++
        return
      }

      if (isItGood[numAttempt]) {
        resolve('All good!')
      } else {
        reject(operation.mainError())
      }
    })
  })
}

async function main() {
  console.log('Start')
  await retryer()
  console.log('End')
}

main()

API

retry.operation([options])

Creates a new RetryOperation object. options is the same as retry.timeouts()'s options, with three additions:

  • forever: Whether to retry forever, defaults to false.
  • unref: Whether to unref the setTimeout's, defaults to false.
  • maxRetryTime: The maximum time (in milliseconds) that the retried operation is allowed to run. Default is Infinity.

retry.timeouts([options])

Returns an array of timeouts. All time options and return values are in milliseconds. If options is an array, a copy of that array is returned.

options is a JS object that can contain any of the following keys:

  • retries: The maximum amount of times to retry the operation. Default is 10. Seting this to 1 means do it once, then retry it once.
  • factor: The exponential factor to use. Default is 2.
  • minTimeout: The number of milliseconds before starting the first retry. Default is 1000.
  • maxTimeout: The maximum number of milliseconds between two retries. Default is Infinity.
  • randomize: Randomizes the timeouts by multiplying with a factor between 1 to 2. Default is false.

The formula used to calculate the individual timeouts is:

Math.min(random * minTimeout * Math.pow(factor, attempt), maxTimeout)

Have a look at this article for a better explanation of approach.

If you want to tune your factor / times settings to attempt the last retry after a certain amount of time, you can use wolfram alpha. For example in order to tune for 10 attempts in 5 minutes, you can use this equation:

screenshot

Explaining the various values from left to right:

  • k = 0 ... 9: The retries value (10)
  • 1000: The minTimeout value in ms (1000)
  • x^k: No need to change this, x will be your resulting factor
  • 5 * 60 * 1000: The desired total amount of time for retrying in ms (5 minutes)

To make this a little easier for you, use wolfram alpha to do the calculations:

http://www.wolframalpha.com/input/?i=Sum%5B1000*x^k%2C+{k%2C+0%2C+9}%5D+%3D+5+*+60+*+1000

retry.createTimeout(attempt, opts)

Returns a new timeout (integer in milliseconds) based on the given parameters.

attempt is an integer representing for which retry the timeout should be calculated. If your retry operation was executed 4 times you had one attempt and 3 retries. If you then want to calculate a new timeout, you should set attempt to 4 (attempts are zero-indexed).

opts can include factor, minTimeout, randomize (boolean) and maxTimeout. They are documented above.

retry.createTimeout() is used internally by retry.timeouts() and is public for you to be able to create your own timeouts for reinserting an item, see issue #13.

retry.wrap(obj, [options], [methodNames])

Wrap all functions of the obj with retry. Optionally you can pass operation options and an array of method names which need to be wrapped.

retry.wrap(obj)

retry.wrap(obj, ['method1', 'method2'])

retry.wrap(obj, {retries: 3})

retry.wrap(obj, {retries: 3}, ['method1', 'method2'])

The options object can take any options that the usual call to retry.operation can take.

new RetryOperation(timeouts, [options])

Creates a new RetryOperation where timeouts is an array where each value is a timeout given in milliseconds.

Available options:

  • forever: Whether to retry forever, defaults to false.
  • unref: Wether to unref the setTimeout's, defaults to false.

If forever is true, the following changes happen:

  • RetryOperation.errors() will only output an array of one item: the last error.
  • RetryOperation will repeatedly use the timeouts array. Once all of its timeouts have been used up, it restarts with the first timeout, then uses the second and so on.

retryOperation.errors()

Returns an array of all errors that have been passed to retryOperation.retry() so far. The returning array has the errors ordered chronologically based on when they were passed to retryOperation.retry(), which means the first passed error is at index zero and the last is at the last index.

retryOperation.mainError()

A reference to the error object that occured most frequently. Errors are compared using the error.message property.

If multiple error messages occured the same amount of time, the last error object with that message is returned.

If no errors occured so far, the value is null.

retryOperation.attempt(fn, timeoutOps)

Defines the function fn that is to be retried and executes it for the first time right away. The fn function can receive an optional currentAttempt callback that represents the number of attempts to execute fn so far.

Optionally defines timeoutOps which is an object having a property timeout in miliseconds and a property cb callback function. Whenever your retry operation takes longer than timeout to execute, the timeout callback function cb is called.

retryOperation.try(fn)

This is an alias for retryOperation.attempt(fn). This is deprecated. Please use retryOperation.attempt(fn) instead.

retryOperation.start(fn)

This is an alias for retryOperation.attempt(fn). This is deprecated. Please use retryOperation.attempt(fn) instead.

retryOperation.retry(error)

Returns false when no error value is given, or the maximum amount of retries has been reached.

Otherwise it returns true, and retries the operation after the timeout for the current attempt number.

retryOperation.stop()

Allows you to stop the operation being retried. Useful for aborting the operation on a fatal error etc.

retryOperation.reset()

Resets the internal state of the operation object, so that you can call attempt() again as if this was a new operation object.

retryOperation.attempts()

Returns an int representing the number of attempts it took to call fn before it was successful.

License

retry is licensed under the MIT license.

Changelog

0.10.0 Adding stop functionality, thanks to @maxnachlinger.

0.9.0 Adding unref functionality, thanks to @satazor.

0.8.0 Implementing retry.wrap.

0.7.0 Some bug fixes and made retry.createTimeout() public. Fixed issues #10, #12, and #13.

0.6.0 Introduced optional timeOps parameter for the attempt() function which is an object having a property timeout in milliseconds and a property cb callback function. Whenever your retry operation takes longer than timeout to execute, the timeout callback function cb is called.

0.5.0 Some minor refactoring.

0.4.0 Changed retryOperation.try() to retryOperation.attempt(). Deprecated the aliases start() and try() for it.

0.3.0 Added retryOperation.start() which is an alias for retryOperation.try().

0.2.0 Added attempts() function and parameter to retryOperation.try() representing the number of attempts it took to call fn().

NPM DownloadsLast 30 Days