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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@kessler/exponential-backoff

v3.0.5

Published

Opinionated modern exponential backoff retry driver

Downloads

105

Readme

@kessler/exponential-backoff

Opinionated modern exponential backoff retry driver

npm status Travis build status Dependency status

As of version 3.x callback support is dropped.

install

npm i -S @kessler/exponential-backoff

simplest example

const backoff = require('@kessler/exponential-backoff')

async function main() {
  
  // if an error is thrown then work will be retried
  // with an appropriate delay
  // after `maxAttempts` is exceeded 
  // an 'operation failed, exceeded maximum attempts' Error
  // is thrown and the retry process stops
  const work = () => httpRequest('http://example.com')
  const response = await backoff(work)
}

changing the retry behavior

const backoff = require('@kessler/exponential-backoff')

async function main() {
  
  const work = () => httpRequest('http://example.com')
  // more details about these options below
  const response = await backoff(work, {
    maxAttempts: 100,
    maxExponent: 10
  })
}

configuration options

  • maxAttempts (Default 100) - maximum number of attempts before giving up. Meaning, if the 100th attempt fails an error will be thrown.
  • throwMaxAttemptsError (Default true) - if set to false, no error will be thrown when maxAttempts is exceeded
  • delayInterval (Default 100) - minimum delay unit, random(0, Math.pow(base, attemptNumber or maxAttempts)) * delayInterval = next delay
  • base (Default 2) - base exponent for backoff algorithm
  • maxExponent (Default 10) - in exponential backoff the number of attempts is used as the exponent, this is the maximum value that can be used even if retries exceed this value
  • unrefTimer (Default false) - retry delay is achieved using setTimeout(). by default it will be unrefed, so the process will not wait for these timers to finish

iteration API

You can also iterate over the attempts for better insight into and control over the process.

const backoff = require('@kessler/exponential-backoff')

async function main() {
  
  const work = () => httpRequest('http://example.com')
  const iterator = backoff.iterator(work /*, { you can provide options here } */)
  
  for await (let attempt of iterator) {
    console.log(`this is attempt #${attempt}`)
    if (attempt > 0) {
      console.log(iterator.lastError)
    }

    if (attempt > 2) {
      break;
    }
  }

  // proceed from attempt #2 until maxAttempts
  for await (let attempt of iterator) {

  }

  console.log(iterator.result)
}

optimized version

The startup code in backoff() has a cost. You can see the code in bench.js. In situations where you need a performence optimization, use the cached version (but remember: preoptimization is the root of all evil!):

const backoff = require('@kessler/exponential-backoff')

async function main() {
  
  const retry = backoff.cached(/* options */)
  const work = () => httpRequest('http://example.com')
  for (let i = 0; i < 1000; i++) {
    const response = await retry(work)
  }
}

also cached iterator:

const backoff = require('@kessler/exponential-backoff')

async function main() {
  
  const createIterator = backoff.cachedIterator(/* options */)
  const work = () => httpRequest('http://example.com')
  for (let i = 0; i < 1000; i++) {
    const iterator = createIterator(work)
    for await (const attempt of iterator) {}
  }
}

infinite max attempts

Specifiying maxAttempts = Infinity can be handy in situations where you want to retry forever or control the maximum attempts dynamically.

This, however, will never through a operation failed, exceeded maximum attempts error and implicitly ignores throwMaxAttemptsError flag

const backoff = require('@kessler/exponential-backoff')

async function main() {
  
  const work = attempt => {
    if (attempt > computeMaxAttemptSomehow()) {
      return
    }

    return httpRequest('http://example.com')
  }
  const response = await backoff(work, { maxAttempts: Infinity })
}

debug log

This module uses debug module. set DEBUG=@kessler/exponential-backoff to show debug messages.

other stuff

This module is based on the wikipedia article for exponential backoff

The use of the word attempt is used in the code instead of retry mostly because of the wikipedia article.

license

MIT © Yaniv Kessler