npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@lumenlabs-dev/fast-node-retry

v0.1.0

Published

Abstraction for exponential and custom retry strategies for failed operations.

Downloads

8

Readme

fast-node-retry

npm version TypeScript License: MIT

A fast, TypeScript-native abstraction for exponential and custom retry strategies for failed operations.

Installation

npm install @lumenlabs-dev/fast-node-retry

Current Status

This module has been fully migrated to TypeScript with complete type safety and is production-ready. All tests pass and the API maintains backward compatibility with the original retry package.

Features

  • Full TypeScript Support - Complete type definitions for enhanced IDE support
  • Performance Optimized - Faster operations with efficient algorithms
  • Exponential Backoff - Configurable retry strategies with exponential backoff
  • Forever Retry - Option to retry indefinitely
  • Custom Timeouts - Fine-grained control over retry timing
  • Method Wrapping - Wrap existing functions with retry logic
  • Dual Package - CommonJS and ESM support

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.

const dns = require('dns');
const retry = require('@lumenlabs-dev/fast-node-retry');

function faultTolerantResolve(address, cb) {
  const 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);
});

With TypeScript:

import * as dns from 'dns';
import * as retry from '@lumenlabs-dev/fast-node-retry';

function faultTolerantResolve(address: string, cb: (err: Error | null, addresses?: string[]) => void): void {
  const operation = retry.operation();

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

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

faultTolerantResolve('nodejs.org', (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.

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

Example with Promises

const retry = require('@lumenlabs-dev/fast-node-retry');

async function fetchWithRetry(url) {
  const operation = retry.operation({
    retries: 3,
    factor: 2,
    minTimeout: 1000,
    maxTimeout: 5000,
  });

  return new Promise((resolve, reject) => {
    operation.attempt(async (currentAttempt) => {
      try {
        console.log(`Attempt ${currentAttempt}`);
        const response = await fetch(url);
        
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        
        const data = await response.json();
        resolve(data);
      } catch (err) {
        if (operation.retry(err)) {
          return; // Will retry
        }
        reject(operation.mainError());
      }
    });
  });
}

fetchWithRetry('https://api.example.com/data')
  .then(data => console.log('Success:', data))
  .catch(err => console.error('Failed:', err));

With async/await:

import * as retry from '@lumenlabs-dev/fast-node-retry';

async function retryableOperation(): Promise<string> {
  const operation = retry.operation({
    retries: 5,
    minTimeout: 1000,
  });

  return new Promise((resolve, reject) => {
    operation.attempt(async (currentAttempt) => {
      try {
        console.log(`Attempt ${currentAttempt}`);
        const result = await someFlakyOperation();
        resolve(result);
      } catch (err) {
        if (operation.retry(err as Error)) {
          return; // Will retry
        }
        reject(operation.mainError());
      }
    });
  });
}

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.

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.

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.

TypeScript Support

This package is written in TypeScript and provides full type definitions out of the box. No need to install separate @types packages.

import * as retry from '@lumenlabs-dev/fast-node-retry';
import type { RetryOptions, RetryOperation } from '@lumenlabs-dev/fast-node-retry';

const options: RetryOptions = {
  retries: 5,
  factor: 2,
  minTimeout: 1000,
  maxTimeout: 60000,
  randomize: true,
};

const operation: RetryOperation = retry.operation(options);

For detailed information about the TypeScript migration, see TYPESCRIPT_MIGRATION.md.

Performance

This fork includes several performance optimizations:

  • Faster array cloning operations
  • Optimized date/time operations using Date.now()
  • Efficient object property spreading
  • Cached array lengths in loops
  • Optimized error array management

All optimizations maintain full backward compatibility with the original API.

License

This package is licensed under the MIT license.

Credits

This package is a TypeScript fork of the original node-retry by Tim Koschützki, with performance improvements and full type safety.

Changelog

0.1.0 (fast-node-retry)

  • Complete TypeScript migration with full type definitions
  • Performance optimizations (faster array operations, Date.now(), etc.)
  • Dual package support (CommonJS + ESM)
  • Test suite migrated to TypeScript
  • Maintained full backward compatibility with original API

Original node-retry 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.
  • 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().