
Security News
MCP Community Begins Work on Official MCP Metaregistry
The MCP community is launching an official registry to standardize AI tool discovery and let agents dynamically find and install MCP servers.
typescript-retry-decorator
Advanced tools
A simple retry decorator for typescript with no dependency.
This is inspired by the Spring-Retry project. Written in Typescript, 100% Test Coverage.
Import and use it. Retry for Promise
is supported as long as the runtime
has promise(nodejs/evergreen-browser).
npm install typescript-retry-decorator
Option Name | Type | Required? | Default | Description |
---|---|---|---|---|
maxAttempts | number | Yes | - | The max attempts to try |
backOff | number | No | 0 | number in ms to back off. If not set, then no wait |
backOffPolicy | enum | No | FixedBackOffPolicy | can be fixed or exponential |
exponentialOption | object | No | { maxInterval: 2000, multiplier: 2 } | This is for the ExponentialBackOffPolicy The max interval each wait and the multiplier for the backOff . For backoffStrategy , more details below |
doRetry | (e: any) => boolean | No | - | Function with error parameter to decide if repetition is necessary. |
value | Error/Exception class | No | [ ] | An array of Exception types that are retryable. |
useConsoleLogger | boolean | No | true | Print errors on console. |
useOriginalError | throw original exception | No | false | MaxAttemptsError by default. if this is set to true, the original exception would be thrown instead. |
The exponentialOption
allows you to fine-tune the exponential backoff strategy using several options:
maxInterval
: The maximum interval between two retries. The default value is 2000 ms.multiplier
: The multiplier to use to generate the next backoff interval from the last one. The default value is 2.backoffStrategy
: Optional. If specified, determines the strategy used to introduce "jitter" between retry intervals. For an explanation of the available strategies and why you might select one over the other, check out this article.
ExponentialBackoffStrategy.FullJitter
: The base backoff interval is multiplied by a random number between 0 and 1.ExponentialBackoffStrategy.EqualJitter
: The backoff interval is (base interval / 2) + (random value between 0 and base interval / 2).import { Retryable, BackOffPolicy } from 'typescript-retry-decorator';
let count: number = 1;
class RetryExample {
@Retryable({ maxAttempts: 3 })
static async noDelayRetry() {
console.info(`Calling noDelayRetry for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new Error('I failed!');
}
@Retryable({
maxAttempts: 3,
value: [SyntaxError, ReferenceError]
})
static async noDelaySpecificRetry(): Promise<void> {
console.info(`Calling noDelaySpecificRetry for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new SyntaxError('I failed with SyntaxError!');
}
@Retryable({
maxAttempts: 3,
backOff: 1000,
doRetry: (e: Error) => {
return e.message === 'Error: 429';
}
})
static async doRetry() {
console.info(`Calling doRetry for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new Error('Error: 429');
}
@Retryable({
maxAttempts: 3,
backOff: 1000,
doRetry: (e: Error) => {
return e.message === 'Error: 429';
}
})
static async doNotRetry() {
console.info(`Calling doNotRetry for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new Error('Error: 404');
}
@Retryable({
maxAttempts: 3,
backOffPolicy: BackOffPolicy.FixedBackOffPolicy,
backOff: 1000
})
static async fixedBackOffRetry() {
console.info(`Calling fixedBackOffRetry 1s for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new Error('I failed!');
}
@Retryable({
maxAttempts: 3,
backOffPolicy: BackOffPolicy.ExponentialBackOffPolicy,
backOff: 1000,
exponentialOption: { maxInterval: 4000, multiplier: 3 }
})
static async ExponentialBackOffRetry() {
console.info(`Calling ExponentialBackOffRetry backOff 1s, multiplier=3 for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new Error('I failed!');
}
@Retryable({
maxAttempts: 3,
backOffPolicy: BackOffPolicy.ExponentialBackOffPolicy,
backOff: 1000,
exponentialOption: { maxInterval: 4000, multiplier: 2, backoffStrategy: ExponentialBackoffStrategy.EqualJitter }
})
static async ExponentialBackOffWithJitterRetry() {
console.info(`Calling ExponentialBackOffWithJitterRetry backOff 1s, multiplier=2 for the ${count++} time at ${new Date().toLocaleTimeString()}`);
throw new Error('I failed!');
}
}
(async () => {
try {
resetCount();
await RetryExample.noDelayRetry();
} catch (e) {
console.info(`All retry done as expected, final message: '${e.message}'`);
}
try {
resetCount();
await RetryExample.doRetry();
} catch (e) {
console.info(`All retry done as expected, final message: '${e.message}'`);
}
try {
resetCount();
await RetryExample.doNotRetry();
} catch (e) {
console.info(`All retry done as expected, final message: '${e.message}'`);
}
try {
resetCount();
await RetryExample.fixedBackOffRetry();
} catch (e) {
console.info(`All retry done as expected, final message: '${e.message}'`);
}
try {
resetCount();
await RetryExample.ExponentialBackOffRetry();
} catch (e) {
console.info(`All retry done as expected, final message: '${e.message}'`);
}
try {
resetCount();
await RetryExample.ExponentialBackOffWithJitterRetry();
} catch (e) {
console.info(`All retry done as expected, final message: '${e.message}'`);
}
})();
function resetCount() {
count = 1;
}
Run the above code with ts-node
, then output will be:
Calling noDelayRetry for the 1 time at 4:12:49 PM
Calling noDelayRetry for the 2 time at 4:12:49 PM
Calling noDelayRetry for the 3 time at 4:12:49 PM
Calling noDelayRetry for the 4 time at 4:12:49 PM
I failed!
All retry done as expected, final message: 'Failed for 'noDelayRetry' for 3 times.'
Calling noDelayRetry for the 1 time at 4:12:49 PM
Calling noDelayRetry for the 2 time at 4:12:49 PM
Calling noDelayRetry for the 3 time at 4:12:49 PM
Calling noDelayRetry for the 4 time at 4:12:49 PM
I failed with SyntaxError!
All retry done as expected, final message: 'Failed for 'noDelaySpecificRetry' for 3 times.'
Calling doRetry for the 1 time at 4:12:49 PM
Calling doRetry for the 2 time at 4:12:50 PM
Calling doRetry for the 3 time at 4:12:51 PM
Calling doRetry for the 4 time at 4:12:52 PM
Error: 429
All retry done as expected, final message: 'Failed for 'doRetry' for 3 times.'
Calling doNotRetry for the 1 time at 4:12:52 PM
All retry done as expected, final message: 'Error: 404'
Calling fixedBackOffRetry 1s for the 1 time at 4:12:52 PM
Calling fixedBackOffRetry 1s for the 2 time at 4:12:53 PM
Calling fixedBackOffRetry 1s for the 3 time at 4:12:54 PM
Calling fixedBackOffRetry 1s for the 4 time at 4:12:55 PM
I failed!
All retry done as expected, final message: 'Failed for 'fixedBackOffRetry' for 3 times.'
Calling ExponentialBackOffRetry backOff 1s, multiplier=3 for the 1 time at 4:12:55 PM
Calling ExponentialBackOffRetry backOff 1s, multiplier=3 for the 2 time at 4:12:56 PM
Calling ExponentialBackOffRetry backOff 1s, multiplier=3 for the 3 time at 4:12:59 PM
Calling ExponentialBackOffRetry backOff 1s, multiplier=3 for the 4 time at 4:13:03 PM
I failed!
All retry done as expected, final message: 'Failed for 'ExponentialBackOffRetry' for 3 times.'
Calling ExponentialBackOffWithJitterRetry backOff 1s, multiplier=2 for the 1 time at 4:13:03 PM
Calling ExponentialBackOffWithJitterRetry backOff 1s, multiplier=2 for the 2 time at 4:13:03 PM
Calling ExponentialBackOffWithJitterRetry backOff 1s, multiplier=2 for the 3 time at 4:13:05 PM
Calling ExponentialBackOffWithJitterRetry backOff 1s, multiplier=2 for the 4 time at 4:13:09 PM
I failed!
All retry done as expected, final message: 'Failed for 'ExponentialBackOffWithJitterRetry' for 3 times.'
FAQs
A simple retry decorator for typescript with no dependency.
The npm package typescript-retry-decorator receives a total of 82,797 weekly downloads. As such, typescript-retry-decorator popularity was classified as popular.
We found that typescript-retry-decorator 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
The MCP community is launching an official registry to standardize AI tool discovery and let agents dynamically find and install MCP servers.
Research
Security News
Socket uncovers an npm Trojan stealing crypto wallets and BullX credentials via obfuscated code and Telegram exfiltration.
Research
Security News
Malicious npm packages posing as developer tools target macOS Cursor IDE users, stealing credentials and modifying files to gain persistent backdoor access.