
Security News
rv Is a New Rust-Powered Ruby Version Manager Inspired by Python's uv
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
The p-retry package is a utility module that allows you to retry a promise-returning or async function. It is useful for handling operations that may fail due to transient errors and can be retried successfully after a short delay. This package provides a simple API to manage the number of retries, the delay between retries, and the condition for retrying.
Basic retry functionality
This code sample demonstrates how to use p-retry to attempt a function that returns a promise up to 5 times before giving up and throwing an error.
const pRetry = require('p-retry');
const runOperation = () => {
return new Promise((resolve, reject) => {
// Your operation here, e.g., a fetch request
if (Math.random() > 0.5) {
resolve('Success!');
} else {
reject(new Error('Failed!'));
}
});
};
pRetry(runOperation, {retries: 5}).then(result => console.log(result)).catch(error => console.error(error));
Custom retry options
This code sample shows how to provide custom retry options such as the number of retries, the backoff factor, and the minimum and maximum timeout between retries. It also demonstrates how to log information about failed attempts.
const pRetry = require('p-retry');
const runOperation = async () => {
// Your async operation here
};
const onFailedAttempt = error => {
console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`);
};
const options = {
onFailedAttempt,
retries: 3,
factor: 2,
minTimeout: 1000,
maxTimeout: 5000
};
pRetry(runOperation, options).catch(error => console.error(error));
Conditional retry
This code sample illustrates how to use p-retry with a conditional check to determine whether to retry the operation based on the type of error encountered. If the error is not an instance of a specific error class, the retry is aborted.
const pRetry = require('p-retry');
const runOperation = async () => {
// Your async operation here
};
const shouldRetry = error => error instanceof SpecificError;
pRetry(runOperation, { retries: 5, onFailedAttempt: error => {
if (!shouldRetry(error)) {
throw new pRetry.AbortError(error);
}
}}).catch(error => console.error(error));
The 'retry' package provides similar functionality to p-retry, allowing you to retry asynchronous functions. It is more low-level and does not return promises, which means it can be more flexible but also requires more boilerplate code to handle asynchronous operations.
The 'async-retry' package is another alternative that offers a similar API to p-retry. It supports both promise-returning and async functions and provides options to customize retry strategies. It is comparable to p-retry but has its own syntax and options for configuration.
The 'retry-as-promised' package is designed to work with promises and provides a mechanism to retry a promise a certain number of times. It is similar to p-retry but has a different API and may offer different options for configuring retries.
Retry a promise-returning or async function
It does exponential backoff and supports custom retry strategies for failed operations.
npm install p-retry
import pRetry, {AbortError} from 'p-retry';
const run = async () => {
const response = await fetch('https://sindresorhus.com/unicorn');
// Abort retrying if the resource doesn't exist
if (response.status === 404) {
throw new AbortError(response.statusText);
}
return response.blob();
};
console.log(await pRetry(run, {retries: 5}));
Returns a Promise
that is fulfilled when calling input
returns a fulfilled promise. If calling input
returns a rejected promise, input
is called again until the max retries are reached, it then rejects with the last rejection reason.
Does not retry on most TypeErrors
, with the exception of network errors. This is done on a best case basis as different browsers have different messages to indicate this. See whatwg/fetch#526 (comment)
Type: Function
Receives the number of attempts as the first argument and is expected to return a Promise
or any value.
Type: object
Type: Function
Callback invoked on each retry. Receives a context object containing the error and retry state information.
import pRetry from 'p-retry';
const run = async () => {
const response = await fetch('https://sindresorhus.com/unicorn');
if (!response.ok) {
throw new Error(response.statusText);
}
return response.json();
};
const result = await pRetry(run, {
onFailedAttempt: ({error, attemptNumber, retriesLeft}) => {
console.log(`Attempt ${attemptNumber} failed. There are ${retriesLeft} retries left.`);
// 1st request => Attempt 1 failed. There are 5 retries left.
// 2nd request => Attempt 2 failed. There are 4 retries left.
// …
},
retries: 5
});
console.log(result);
The onFailedAttempt
function can return a promise. For example, to add a delay:
import pRetry from 'p-retry';
import delay from 'delay';
const run = async () => { … };
const result = await pRetry(run, {
onFailedAttempt: async () => {
console.log('Waiting for 1 second before retrying');
await delay(1000);
}
});
If the onFailedAttempt
function throws, all retries will be aborted and the original promise will reject with the thrown error.
Type: Function
Decide if a retry should occur based on the context. Returning true triggers a retry, false aborts with the error.
It is only called if retries
and maxRetryTime
have not been exhausted.
It is not called for TypeError
(except network errors) and AbortError
.
import pRetry from 'p-retry';
const run = async () => { … };
const result = await pRetry(run, {
shouldRetry: ({error, attemptNumber, retriesLeft}) => !(error instanceof CustomError)
});
In the example above, the operation will be retried unless the error is an instance of CustomError
.
Type: number
Default: 10
The maximum amount of times to retry the operation.
Type: number
Default: 2
The exponential factor to use.
Type: number
Default: 1000
The number of milliseconds before starting the first retry.
Type: number
Default: Infinity
The maximum number of milliseconds between two retries.
Type: boolean
Default: false
Randomizes the timeouts by multiplying with a factor between 1 and 2.
Type: number
Default: Infinity
The maximum time (in milliseconds) that the retried operation is allowed to run.
Type: AbortSignal
You can abort retrying using AbortController
.
import pRetry from 'p-retry';
const run = async () => { … };
const controller = new AbortController();
cancelButton.addEventListener('click', () => {
controller.abort(new Error('User clicked cancel button'));
});
try {
await pRetry(run, {signal: controller.signal});
} catch (error) {
console.log(error.message);
//=> 'User clicked cancel button'
}
Type: boolean
Default: false
Prevents retry timeouts from keeping the process alive.
Only affects platforms with a .unref()
method on timeouts, such as Node.js.
Wrap a function so that each call is automatically retried on failure.
import {makeRetriable} from 'p-retry';
const fetchWithRetry = makeRetriable(fetch, {retries: 5});
const response = await fetchWithRetry('https://sindresorhus.com/unicorn');
Abort retrying and reject the promise.
Type: string
An error message.
Type: Error
A custom error.
You can pass arguments to the function being retried by wrapping it in an inline arrow function:
import pRetry from 'p-retry';
const run = async emoji => {
// …
};
// Without arguments
await pRetry(run, {retries: 5});
// With arguments
await pRetry(() => run('🦄'), {retries: 5});
The package uses setTimeout
and clearTimeout
from the global scope, so you can use the Node.js test timer mocking or a package like sinon
.
Use an AbortController
to signal cancellation on SIGINT, and pass its signal
to pRetry
:
import pRetry from 'p-retry';
const controller = new AbortController();
process.once('SIGINT', () => {
controller.abort(new Error('SIGINT received'));
});
try {
await pRetry(run, {signal: controller.signal});
} catch (error) {
console.log('Retry stopped due to:', error.message);
}
The package does not handle process signals itself to avoid global side effects.
FAQs
Retry a promise-returning or async function
The npm package p-retry receives a total of 16,212,128 weekly downloads. As such, p-retry popularity was classified as popular.
We found that p-retry demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.
Security News
AGENTS.md is a fast-growing open format giving AI coding agents a shared, predictable way to understand project setup, style, and workflows.