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

ts-retry-promise

v0.8.1

Published

retry for functions returning a promise

Downloads

2,051,067

Readme

ts-retry-promise

Build Status Coverage Status Dependencies NPM

retry for functions returning a promise

Changelog

Usage

Install with yarn: yarn add ts-retry-promise

Install with npm: npm install --save ts-retry-promise

Then you can import it with:

import { retry } from 'ts-retry-promise';

const result: number = await retry(() => Promise.resolve(1), {retries: 3});

This will instantly start calling your function until it returns a resolved promise, no retries are left or a timeout occurred.

If you want to add retries to an existing function, use the decorator:

import { retryDecorator } from 'ts-retry-promise';

const asyncFunction = async (s: String) => s;

const decoratedFunction = retryDecorator(asyncFunction, {timeout: 1});

const result: string = await decoratedFunction("1");

Here decoratedFunction is a function with the same signature as asyncFunction, but will do retries in case of failures.

Configuration

Both retry and retryDecorator take an optional second argument where you can configure the number of retries and timeouts:

export interface RetryConfig<T> {
    // number of maximal retry attempts (default: 10)
    retries?: number | "INFINITELY";

    // wait time between retries in ms (default: 100)
    delay?: number;

    // check the result, will retry until true (default: () => true)
    until?: (t: T) => boolean;

    // log events (default: () => undefined)
    logger?: (msg: string) => void;

    // overall timeout in ms (default: 60 * 1000)
    timeout?: number | "INFINITELY";

    // increase delay with every retry (default: "FIXED")
    backoff?: "FIXED" | "EXPONENTIAL" | "LINEAR" | ((attempt: number, delay: number) => number);

    // maximal backoff in ms (default: 5 * 60 * 1000)
    maxBackOff?: number;

    // allows to abort retrying for certain errors, will retry until false (default: () => true)
    retryIf: (error: any) => boolean
}

Customize

customizeRetry returns a new instance of retry that has the defined default configuration.

import { customizeRetry } from 'ts-retry-promise'; 

const impatientRetry = customizeRetry({timeout: 5});

await expect(impatientRetry(async () => wait(10))).to.be.rejectedWith("Timeout");

// another example

const retryUntilNotEmpty = customizeRetry({until: (array: any[]) => array.length > 0});

const result = await retryUntilNotEmpty(async () => [1, 2]);

expect(result).to.deep.eq([1, 2]);

You can do the same for decorators:

import { customizeDecorator } from 'ts-retry-promise'; 

const asyncFunction = async (s: string) => {
    await wait(3);
    return s;
};

const impatientDecorator = customizeDecorator({timeout: 1});

expect(impatientDecorator(asyncFunction)("1")).to.be.rejectedWith("Timeout");

Failure

In case retry failed, an error is thrown. You can access the error that occurred the last time the function has been retried via the property lastError:

retry(async () => throw "1")
    .catch(err => console.log(err.lastError)); // will print "1" 

NotRetryableError

Wrapped function can throw NotRetryableError if retrying need to be stopped eventually:

import { NotRetryableError } from 'ts-retry-promise';

retry(async () => { throw new NotRetryableError("This error") }, { retries: 'INFINITELY' })
    .catch(err => console.log(err.lastError.message));  // will print "This error"

Samples

retryDecorator can be used on any function that returns a promise

const loadUserProfile: (id: number) => Promise<{ name: string }> = async id => ({name: "Mr " + id});

const robustProfileLoader = retryDecorator(loadUserProfile, {retries: 2});

const profile = await robustProfileLoader(123);

retry is well suited for acceptance tests (but not restricted to)

// ts-retry-promise/test/retry-promise.demo.test.ts
it("will retry until no exception or limit reached", async () => {

    await retry(async () => {
        const title = await browser.$("h1");
        expect(title).to.eq("Loaded");
    });

});

it("can return a result", async () => {

    const pageTitle = await retry(async () => {
        const title = await browser.$("h1");
        expect(title).to.be.not.empty;
        return title;
    });

    // do some stuff with the result
    expect(pageTitle).to.eq("Loaded");
});

it("can be configured and has defaults", async () => {

    await retry(async () => {
        // your code
    }, {backoff: "LINEAR", retries: 100});

});

it("will retry until condition is met or limit reached", async () => {

    await retry(
        () => browser.$$("ul"),
        {until: (list) => list.length === 2});

});

it("can have a timeout", async () => {

    const promise = retry(
        () => wait(100),
        {timeout: 10},
    );

    await expect(promise).to.be.rejectedWith("Timeout");
});

it("can create a customized retry", async () => {
    const impatientRetry = customizeRetry({timeout: 5});

    await expect(impatientRetry(async () => wait(10))).to.be.rejectedWith("Timeout");
});

it("can create another customized retry", async () => {
    const retryUntilNotEmpty = customizeRetry({until: (array: number[]) => array.length > 0});

    const result = await retryUntilNotEmpty(async () => [1, 2]);

    expect(result).to.deep.eq([1, 2]);
});

it("can customize default config", async () => {
    const originalTimeout = defaultRetryConfig.timeout;
    try {
        defaultRetryConfig.timeout = 1;

        await expect(retry(async () => wait(10))).to.be.rejectedWith("Timeout");
    } finally {
        defaultRetryConfig.timeout = originalTimeout;
    }
});

Release instructions

Release automation has been setup according this guide.

  1. Create a Github release with version tag like 0.6.1.
  2. Check the new version exists on npmjs.com/package/ts-retry-promise and has latest tag.