insistent v1.3.4
Insistent
NOTE: insistent
has been rebranded to @coderspirit/insistent
,
use that new package instead.
Small Typescript library that implements retries & other related features to execute fallible functions (no matter if they are asynchronous or synchronous).
Why another retry-stuff package?
Insistent tries to meet a small set of requirements that were not fulfilled concurrently by other libraries:
- To be fully typed.
- To provide retry & throw lists against error types, to simplify retry logic.
- To have a high testing coverage.
- To be tested against all the NodeJS active versions.
- To ensure its dependencies are kept up to date.
Insistent for enterprise
Available as part of the Tidelift Subscription
The maintainers of insistent and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. Learn more.
Installation
$ npm install @coderspirit/insistent
Usage
The function insist
is asynchronous, so its response will always be a
Promise
instance, which is easily managed through the await
syntax.
Typescript examples:
import { insist, InsistPolicy } from 'insistent'
import { fn } from './your/module'
const basicExample = async () => {
// We wrap 'fn' with a parameter-less lambda, so we can feed it into 'insist'.
// 'insist' will do all the retry magic for us.
const result = await insist(() => fn(1, 2, 3))
}
const configurationExample = async () => {
const result = await insist(() => fn(1, 2, 3), {
// We can pass all these OPTIONAL configuration parameters
maxRetries: 5, // Maximum amount of retries
retryInterval: 1000, // Measured in ms, initial time between retries (it can change)
intervalIncrements: 1000, // Measured in ms, each retry the waiting interval increases by this amount
maxRetryInterval: 15000, // Measured in ms, we can decide to cap the time between retries
insistPolicy: InsistPolicy.RETRY, // It can be THROW as well, RETRY is the default behaviour
alwaysRetryOn: [RecoverableErrorA, RecoverableErrorB], // We can set recoverable error types here, [] by default
alwaysThrowOn: [FatalErrorA, FatalErrorB], // Errors for which we don't want to retry, [] by default
// If alwaysRetryOn or alwaysThrowOn were not flexible enough, you can pass a function to decide if throw or retry
// using more complex criteria.
// Returning ErrorHandlingStrategy.RETRY will force a retry
// Returning ErrorHandlingStrategy.THROW will force a throw
// Returning null will let 'insist' to rely on its default strategy and the alwaysRetryOn & alwaysThrowOn lists.
errorClassifier: (e: Error) => {
return e.message === 'You should retry' ? InsistPolicy.RETRY : null
}
})
}
const dynamicRetryIntervalExample = async () => {
// If we define a second parameter for the errorClassifier function, we'll be able to tell 'insist' for how long we
// should wait before retrying again. This could be useful, for example, when dealing with HTTP status like 429.
const result = await insist(() => fn(1, 2, 3), {
errorClassifier: (e: Error, setRetryAfter: (t: number) => void) => {
// This HttpError type is hypothetical
if (e instanceof HttpError && e.code === 429) {
// This tells insist for how long we should wait. If, for whatever reason, we pass something which is not zero
// nor a positive number, it will fallback to retryInterval plus a multiple of intervalIncrements.
setRetryAfter(Number(e.headers['Retry-After']))
return InsistPolicy.RETRY
}
return null
}
})
}
License
Released under the MIT License.