ts-retry-promise v0.8.1
ts-retry-promise
retry for functions returning a promise
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.
- Create a Github release with version tag like
0.6.1. - Check the new version exists on npmjs.com/package/ts-retry-promise and has
latesttag.
2 years ago
2 years ago
2 years ago
3 years ago
3 years ago
4 years ago
5 years ago
5 years ago
6 years ago
6 years ago
6 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago