retry vs promise-retry vs async-retry vs wait-for-expect vs promise-poller
JavaScript Retry Mechanisms Comparison
1 Year
retrypromise-retryasync-retrywait-for-expectpromise-pollerSimilar Packages:
What's JavaScript Retry Mechanisms?

These npm packages provide various strategies for retrying asynchronous operations in JavaScript, particularly useful in scenarios where operations may fail due to transient errors, such as network requests or database queries. They help ensure that applications can gracefully handle failures and improve reliability by automatically retrying failed operations based on defined rules and conditions.

Package Weekly Downloads Trend
Github Stars Ranking
Stat Detail
Package
Downloads
Stars
Size
Issues
Publish
License
retry40,096,2411,242-194 years agoMIT
promise-retry15,135,966314-115 years agoMIT
async-retry9,944,2401,865-304 years agoMIT
wait-for-expect581,436296-125 years agoMIT
promise-poller24,432117-85 years agoMIT
Feature Comparison: retry vs promise-retry vs async-retry vs wait-for-expect vs promise-poller

Retry Logic

  • retry:

    retry is a versatile package that can handle both synchronous and asynchronous functions. It allows you to define retry strategies, including maximum attempts and delays, and provides a straightforward API for implementing retries across various use cases.

  • promise-retry:

    promise-retry provides a simple way to retry promise-returning functions with customizable retry logic. You can specify the number of retries, delay between attempts, and handle specific error cases, making it effective for handling failures in asynchronous operations.

  • async-retry:

    async-retry offers a flexible retry logic that allows you to specify the number of attempts, delay between retries, and custom error handling. It supports exponential backoff strategies, making it suitable for handling transient errors in network requests or database operations.

  • wait-for-expect:

    wait-for-expect is tailored for testing scenarios, allowing you to wait for specific expectations to be met in asynchronous tests. It simplifies the process of writing tests that involve asynchronous operations, ensuring that your assertions are only checked when the expected conditions are satisfied.

  • promise-poller:

    promise-poller implements a polling mechanism that repeatedly invokes a promise-returning function until a specified condition is met. It allows you to define the polling interval and timeout, making it ideal for scenarios where you need to wait for a resource to become available.

Use Cases

  • retry:

    Useful for a wide range of applications that require retries for both synchronous and asynchronous operations, including database queries and external service calls.

  • promise-retry:

    Great for retrying operations that may fail due to temporary issues, such as API calls, where you want to implement a simple retry mechanism without complex configurations.

  • async-retry:

    Best suited for applications that make frequent network requests or interact with unreliable services, where transient failures are common and need to be handled gracefully with retries.

  • wait-for-expect:

    Specifically designed for testing frameworks, making it essential for writing tests that involve asynchronous operations and ensuring that your tests are reliable and accurate.

  • promise-poller:

    Ideal for scenarios where you need to check the status of an operation or resource repeatedly until it becomes available, such as waiting for a file to be uploaded or a service to be ready.

Configuration Flexibility

  • retry:

    Flexible in defining retry strategies, allowing for detailed configurations that can adapt to various use cases, whether for synchronous or asynchronous functions.

  • promise-retry:

    Offers straightforward configuration options for retries, including the number of attempts and delay, making it easy to implement without extensive setup.

  • async-retry:

    Highly configurable, allowing developers to customize retry attempts, delays, and error handling strategies to fit specific application needs. It supports both linear and exponential backoff strategies.

  • wait-for-expect:

    Simplifies configuration for test scenarios, allowing developers to specify the conditions and timeouts for expectations in a clear and concise manner.

  • promise-poller:

    Provides options for customizing polling intervals and timeouts, giving developers control over how often to check for conditions and how long to wait before giving up.

Error Handling

  • retry:

    Offers robust error handling capabilities, enabling developers to specify retry conditions based on error types, making it suitable for complex error scenarios.

  • promise-retry:

    Provides mechanisms to handle errors during retries, allowing developers to specify which errors should trigger a retry and how to manage them effectively.

  • async-retry:

    Includes built-in support for handling specific errors, allowing developers to define which errors should trigger a retry and which should not, enhancing control over the retry process.

  • wait-for-expect:

    Focuses on ensuring that expectations are met before proceeding, providing clear error messages when expectations fail, which is crucial for debugging tests.

  • promise-poller:

    Handles errors gracefully by allowing the polling to continue until the condition is met or the timeout is reached, ensuring that transient errors do not halt the polling process.

Learning Curve

  • retry:

    Moderate learning curve due to its versatility and broader use cases. However, once understood, it can be applied to various scenarios effectively.

  • promise-retry:

    Very easy to grasp, with a minimalistic API that allows developers to implement retries with just a few lines of code, making it suitable for quick solutions.

  • async-retry:

    Relatively easy to learn, especially for developers familiar with promises and async/await syntax. Its API is straightforward and intuitive, making it accessible for quick implementation.

  • wait-for-expect:

    Designed for developers familiar with testing frameworks, it has a straightforward API that integrates seamlessly into test cases, making it easy to adopt.

  • promise-poller:

    Simple to understand and use, especially for those familiar with polling concepts. The API is designed to be user-friendly, allowing for quick integration into projects.

How to Choose: retry vs promise-retry vs async-retry vs wait-for-expect vs promise-poller
  • retry:

    Opt for retry when you want a more general-purpose retry mechanism that can handle both synchronous and asynchronous functions. It provides a robust API for defining retry strategies and is useful for retrying operations that may not return promises.

  • promise-retry:

    Use promise-retry if you want a straightforward way to retry promise-returning functions with a focus on handling errors and customizing the retry logic. It allows for a simple configuration of retries and delays, making it suitable for straightforward retry needs.

  • async-retry:

    Choose async-retry if you need a simple and flexible way to retry asynchronous functions with customizable retry strategies, including delays and maximum attempts. It is particularly useful for handling promises and async/await syntax.

  • wait-for-expect:

    Choose wait-for-expect if you are writing tests and need a way to wait for asynchronous expectations to be met. This package is specifically designed for testing frameworks and helps ensure that your tests only proceed once certain conditions are satisfied.

  • promise-poller:

    Select promise-poller when you need to repeatedly execute a promise-returning function until a certain condition is met, providing a polling mechanism that can be customized with intervals and timeouts. It's ideal for scenarios where you want to wait for a resource to become available.

README for retry

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,
});

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().