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

@webinmove/nyuma

v1.3.1

Published

Retry an async function with different strategies

Downloads

68

Readme

Nyuma

Continuous Integration Coverage Status npm version Dependency Status

Description

Nyuma means "back" in Swahili. It is an async retry implementation with fibonacci or exponential strategy.

Motivation

All the backoff implementation I came accross where missing on key feature: a maximum overall time option.

Installation

$ npm install @webinmove/nyuma

Usage

Basic real life

const { fibonacci } = require('@webinmove/nyuma');
const fetch = require('node-fetch');

const main = async () => {
  const nyuma = fibonacci({ initialDelay: 100, maxTime: 60000 });

  try {
    // Here we'll only retry on real network error
    const response = await nyuma.start(() =>
      fetch('https://api.github.com/repos/webinmove/nyuma')
    );
    console.log(await response.json());
  } catch (err) {
    // Couldn't get the response in less than a minute...
    console.error(err);
  }
};

main();

With another strategy and more options

const { exponential } = require('@webinmove/nyuma');
const fetch = require('node-fetch');

const main = async () => {
  const nyuma = exponential({
    initialDelay: 100,
    maxDelay: 10000,
    maxRetries: 3,
    maxTime: 60000,
    maxTimeError: 'First fetch was too long',
    factor: 3
  });

  try {
    const body = await nyuma
      .retryHook(({ error, retryCount, lastDelay, duration }) =>
        console.log('Retry with:', { error, retryCount, lastDelay, duration })
      )
      .failHook(({ reason, retryCount, lastDelay, duration }) =>
        console.log('Failed with:', { reason, retryCount, lastDelay, duration })
      )
      .start(async () => {
        const response = await fetch('https://api.github.com/repos/webinmove/nyuma');
        if (response.status >= 400) {
          throw new Error(`Call responded with status ${response.status}`);
        }

        return response.json();
      });

    console.log(body);
  } catch (err) {
    // Couldn't get the response in less than a minute or 5 retries...
    console.error(err);
  }
};

main();

Using base classes

const { Nyuma, ExponentialStrategy } = require('@webinmove/nyuma');

const fetch = require('node-fetch');

const main = async () => {
  const strategy = new ExponentialStrategy({ factor: 3 });
  const nyuma = new Nyuma({
    strategy,
    initialDelay: 100,
    maxDelay: 10000,
    maxRetries: 3,
    maxTime: 60000
  });

  nyuma.failHook(({ reason, retryCount, lastDelay, duration }) =>
    console.log({ reason, retryCount, lastDelay, duration })
  );

  try {
    const body = await nyuma.start(async () => {
      const response = await fetch('https://api.github.com/repos/webinmove/nyuma');
      if (response.status >= 400) {
        throw new Error(`Call responded with status ${response.status}`);
      }

      return response.json();
    });

    console.log(body);
  } catch (err) {
    // Couldn't get the response in less than a minute or 5 retries...
    console.error(err);
  }
};

main();

API

fibonacci(params)

Returns a Nyuma instance initialized with the fibonacci strategy and the params.

params

  • initialDelay: delay in ms for the first retry (required)
  • maxDelay: maximum delay can reach before a retry (optional, default Infinity)
  • maxRetries: maximum retries before throwing the last error encounter (optional, default Infinity)
  • maxTime: maximum time for the first try and all retries before throwing the last error encounter or a specific error if the first try was too long (optional, default Infinity)
  • maxTimeError: error message in case the first try was too long (optional, dafault "First try reached max time")

Note: you should specify at least a maxRetries or a maxTime

exponential(params)

Returns a Nyuma instance initialized with the exponential strategy and the params.

params

  • factor: exponential factor used to compute the delays (optional, default 2)
  • initialDelay: delay in ms for the first retry (required)
  • maxDelay: maximum delay can reach before a retry (optional, default Infinity)
  • maxRetries: maximum retries before throwing the last error encounter (optional, default Infinity)
  • maxTime: maximum time for the first try and all retries before throwing the last error encounter or a specific error if the first try was too long (optional, default Infinity)
  • maxTimeError: error message in case the first try was too long (optional, dafault "First try reached max time")

Note: you should specify at least a maxRetries or a maxTime

Class Nyuma

constructor(params)

Returns a Nyuma instance initialized with the params.

params

  • strategy: a strategy instance (optional, default exponentialStrategy)
  • initialDelay: delay in ms for the first retry (required)
  • maxDelay: maximum delay can reach before a retry (optional, default Infinity)
  • maxRetries: maximum retries before throwing the last error encounter (optional, default Infinity)
  • maxTime: maximum time for the first try and all retries before throwing the last error encounter or a specific error if the first try was too long (optional, default Infinity)
  • maxTimeError: error message in case the first try was too long (optional, dafault "First try reached max time")

Note: you should specify at least a maxRetries or a maxTime

start(fn)

Start the retry process retruning a promise of the fn result.

  • fn: a function that will be retry until sucess or a maximum reached (required)

When called this function will have 2 arguments:

  • retryCount: number of retry already done
  • lastDelay: delay between the previous retry and the current

exemple:

const { Nyuma, FibonacciStrategy } = require('@webinmove/nyuma');

const main = async () => {
  const strategy = new FibonacciStrategy();
  const nyuma = new Nyuma({ strategy, initialDelay: 10, maxRetries: 10 });

  await nyuma.start(async (retryCount, lastDelay) => {
    console.log(`${retryCount} ${lastDelay} ms`);
    throw new Error('Try again!');
  }
  );
};

main();

will output:

0 0 ms
1 10 ms
2 10 ms
3 20 ms
4 30 ms
5 50 ms
6 80 ms
7 130 ms
8 210 ms
9 340 ms
10 550 ms
(node:51869) UnhandledPromiseRejectionWarning: Error: Try again!

failHook(fn)

Set a function on fail hook function.

  • fn: a function that will be called on fail.

When called this function will have 1 argument:

  • params: object containing
    • reason: string with the fail reason (e.g. "Maximum retry reached" or "Maximum time reached")
    • retryCount: number of retry done until fail
    • lastDelay: last retry delay in ms
    • duration: overall duration before fail in ms

Class ExponentialStrategy

constructor(params)

Returns a ExponentialStrategy instance initialized with the params.

params

  • factor: the multiplicator factor, should be >= 1 (optional, default 2)

next()

Retruns the next iteration of the exponential sequence (e.g.: 1, 2, 4, 8, ...).

Class FibonacciStrategy

constructor()

Returns a FibonacciStrategy instance initialized with the params.

next()

Retruns the next iteration of the fibonacci sequence (e.g.: 1, 1, 2, 3, 5, 8, ...).

Npm scripts

Running code formating

$ npm run format

Running tests

$ npm run test:spec

Running lint tests

$ npm run test:lint

Running coverage tests

$ npm run test:cover

This will create a coverage folder with all the report in coverage/index.html

Running all tests

$ npm test

Note: that's the one you want to use most of the time

Reporting bugs and contributing

If you want to report a bug or request a feature, please open an issue. If want to help us improve nyuma, fork and make a pull request. Please use commit format as described here. And don't forget to run npm run format before pushing commit.