Security News
Research
Data Theft Repackaged: A Case Study in Malicious Wrapper Packages on npm
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Abstraction for exponential and custom retry strategies for failed operations.
The retry npm package provides a set of functions for implementing retry behavior in your code. This is particularly useful when dealing with operations that may fail due to transient errors, such as network requests, database operations, or any other tasks that might not succeed on the first attempt. The package allows you to customize the retry strategy, including the number of attempts, the interval between attempts, and the criteria for retrying.
Simple retry operation
This code sample demonstrates how to perform a simple retry operation. It uses the `operation.attempt` method to try an operation that might fail. If the operation fails, it uses `operation.retry` to determine if a retry should be attempted based on the current strategy.
const retry = require('retry');
const operation = retry.operation();
operation.attempt(currentAttempt => {
performSomeOperation(error => {
if (error) {
if (operation.retry(error)) {
return;
}
console.error('Operation failed:', error);
} else {
console.log('Operation succeeded');
}
});
});
Custom retry strategy
This code sample shows how to set up a custom retry strategy with specific options such as the number of retries, the backoff factor, and the minimum and maximum timeout between retries. The `randomize` option adds some randomness to the retry intervals to prevent overloading the server.
const retry = require('retry');
const operation = retry.operation({
retries: 5,
factor: 3,
minTimeout: 1 * 1000,
maxTimeout: 60 * 1000,
randomize: true
});
operation.attempt(currentAttempt => {
performSomeOperation(error => {
if (error) {
if (operation.retry(error)) {
return;
}
console.error('Operation failed after ' + currentAttempt + ' attempts:', error);
} else {
console.log('Operation succeeded on attempt ' + currentAttempt);
}
});
});
The async-retry package provides similar functionality to retry, but with a focus on async/await syntax. It allows you to wrap asynchronous functions in a retry mechanism with a simple and clean API.
p-retry is a package that offers retry functionality for promises. It is designed to work seamlessly with async functions and provides a declarative way to retry asynchronous operations that return promises.
retry-axios is an adapter for the axios HTTP client that introduces retry functionality. It is specifically tailored for HTTP requests and integrates directly with axios, allowing you to add retry behavior to your HTTP requests with minimal configuration.
Abstraction for exponential and custom retry strategies for failed operations.
npm install retry
This module has been tested and is ready to be used.
The example below will retry a potentially failing dns.resolve
operation
10
times using an exponential backoff strategy. With the default settings, this
means the last attempt is made after 17 minutes and 3 seconds
.
var dns = require('dns');
var retry = require('retry');
function faultTolerantResolve(address, cb) {
var operation = retry.operation();
operation.attempt(function(currentAttempt) {
dns.resolve(address, function(err, addresses) {
if (operation.retry(err)) {
return;
}
cb(err ? operation.mainError() : null, addresses);
});
});
}
faultTolerantResolve('nodejs.org', function(err, addresses) {
console.log(err, addresses);
});
Of course you can also configure the factors that go into the exponential backoff. See the API documentation below for all available settings. currentAttempt is an int representing the number of attempts so far.
var operation = retry.operation({
retries: 5,
factor: 3,
minTimeout: 1 * 1000,
maxTimeout: 60 * 1000,
randomize: true,
});
Creates a new RetryOperation
object. options
is the same as retry.timeouts()
's options
, with three additions:
forever
: Whether to retry forever, defaults to false
.unref
: Whether to unref the setTimeout's, defaults to false
.maxRetryTime
: The maximum time (in milliseconds) that the retried operation is allowed to run. Default is Infinity
.Returns an array of timeouts. All time options
and return values are in
milliseconds. If options
is an array, a copy of that array is returned.
options
is a JS object that can contain any of the following keys:
retries
: The maximum amount of times to retry the operation. Default is 10
. Seting this to 1
means do it once, then retry it once
.factor
: The exponential factor to use. Default is 2
.minTimeout
: The number of milliseconds before starting the first retry. Default is 1000
.maxTimeout
: The maximum number of milliseconds between two retries. Default is Infinity
.randomize
: Randomizes the timeouts by multiplying with a factor between 1
to 2
. Default is false
.The formula used to calculate the individual timeouts is:
Math.min(random * minTimeout * Math.pow(factor, attempt), maxTimeout)
Have a look at this article for a better explanation of approach.
If you want to tune your factor
/ times
settings to attempt the last retry
after a certain amount of time, you can use wolfram alpha. For example in order
to tune for 10
attempts in 5 minutes
, you can use this equation:
Explaining the various values from left to right:
k = 0 ... 9
: The retries
value (10)1000
: The minTimeout
value in ms (1000)x^k
: No need to change this, x
will be your resulting factor5 * 60 * 1000
: The desired total amount of time for retrying in ms (5 minutes)To make this a little easier for you, use wolfram alpha to do the calculations:
http://www.wolframalpha.com/input/?i=Sum%5B1000*x^k%2C+{k%2C+0%2C+9}%5D+%3D+5+*+60+*+1000
Returns a new timeout
(integer in milliseconds) based on the given parameters.
attempt
is an integer representing for which retry the timeout should be calculated. If your retry operation was executed 4 times you had one attempt and 3 retries. If you then want to calculate a new timeout, you should set attempt
to 4 (attempts are zero-indexed).
opts
can include factor
, minTimeout
, randomize
(boolean) and maxTimeout
. They are documented above.
retry.createTimeout()
is used internally by retry.timeouts()
and is public for you to be able to create your own timeouts for reinserting an item, see issue #13.
Wrap all functions of the obj
with retry. Optionally you can pass operation options and
an array of method names which need to be wrapped.
retry.wrap(obj)
retry.wrap(obj, ['method1', 'method2'])
retry.wrap(obj, {retries: 3})
retry.wrap(obj, {retries: 3}, ['method1', 'method2'])
The options
object can take any options that the usual call to retry.operation
can take.
Creates a new RetryOperation
where timeouts
is an array where each value is
a timeout given in milliseconds.
Available options:
forever
: Whether to retry forever, defaults to false
.unref
: Wether to unref the setTimeout's, defaults to false
.If forever
is true, the following changes happen:
RetryOperation.errors()
will only output an array of one item: the last error.RetryOperation
will repeatedly use the timeouts
array. Once all of its timeouts have been used up, it restarts with the first timeout, then uses the second and so on.Returns an array of all errors that have been passed to retryOperation.retry()
so far. The
returning array has the errors ordered chronologically based on when they were passed to
retryOperation.retry()
, which means the first passed error is at index zero and the last is
at the last index.
A reference to the error object that occured most frequently. Errors are
compared using the error.message
property.
If multiple error messages occured the same amount of time, the last error object with that message is returned.
If no errors occured so far, the value is null
.
Defines the function fn
that is to be retried and executes it for the first
time right away. The fn
function can receive an optional currentAttempt
callback that represents the number of attempts to execute fn
so far.
Optionally defines timeoutOps
which is an object having a property timeout
in miliseconds and a property cb
callback function.
Whenever your retry operation takes longer than timeout
to execute, the timeout callback function cb
is called.
This is an alias for retryOperation.attempt(fn)
. This is deprecated. Please use retryOperation.attempt(fn)
instead.
This is an alias for retryOperation.attempt(fn)
. This is deprecated. Please use retryOperation.attempt(fn)
instead.
Returns false
when no error
value is given, or the maximum amount of retries
has been reached.
Otherwise it returns true
, and retries the operation after the timeout for
the current attempt number.
Allows you to stop the operation being retried. Useful for aborting the operation on a fatal error etc.
Resets the internal state of the operation object, so that you can call attempt()
again as if this was a new operation object.
Returns an int representing the number of attempts it took to call fn
before it was successful.
retry is licensed under the MIT license.
0.10.0 Adding stop
functionality, thanks to @maxnachlinger.
0.9.0 Adding unref
functionality, thanks to @satazor.
0.8.0 Implementing retry.wrap.
0.7.0 Some bug fixes and made retry.createTimeout() public. Fixed issues #10, #12, and #13.
0.6.0 Introduced optional timeOps parameter for the attempt() function which is an object having a property timeout in milliseconds and a property cb callback function. Whenever your retry operation takes longer than timeout to execute, the timeout callback function cb is called.
0.5.0 Some minor refactoring.
0.4.0 Changed retryOperation.try() to retryOperation.attempt(). Deprecated the aliases start() and try() for it.
0.3.0 Added retryOperation.start() which is an alias for retryOperation.try().
0.2.0 Added attempts() function and parameter to retryOperation.try() representing the number of attempts it took to call fn().
FAQs
Abstraction for exponential and custom retry strategies for failed operations.
The npm package retry receives a total of 30,881,275 weekly downloads. As such, retry popularity was classified as popular.
We found that retry demonstrated a not healthy version release cadence and project activity because the last version was released 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
Research
The Socket Research Team breaks down a malicious wrapper package that uses obfuscation to harvest credentials and exfiltrate sensitive data.
Research
Security News
Attackers used a malicious npm package typosquatting a popular ESLint plugin to steal sensitive data, execute commands, and exploit developer systems.
Security News
The Ultralytics' PyPI Package was compromised four times in one weekend through GitHub Actions cache poisoning and failure to rotate previously compromised API tokens.