Skip to content

Instantly share code, notes, and snippets.

@tiagobnobrega
Created December 3, 2021 12:16
Show Gist options
  • Save tiagobnobrega/9f369aa857016f0cbf97724dc25707f9 to your computer and use it in GitHub Desktop.
Save tiagobnobrega/9f369aa857016f0cbf97724dc25707f9 to your computer and use it in GitHub Desktop.
Retry async function
type JitterStrategy = "static" | "incremental" | "random";
export interface AsyncRetryOptions {
maxAttempts?: number;
jitterInterval?: number; //time in ms
jitterIncrement?: number; // percent or time in ms
jitterStrategy?: JitterStrategy;
}
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const jitterStrategies: Record<JitterStrategy, (currentAttempt: number, options: AsyncRetryOptions) => Promise<void>> = {
async incremental(currentAttempt: number, options: AsyncRetryOptions): Promise<void> {
const { jitterIncrement = 200, jitterInterval = 100 } = options;
const waitTime = jitterIncrement > 1 ? jitterInterval + jitterIncrement : jitterInterval * (1 + jitterIncrement * currentAttempt);
await sleep(waitTime);
},
async random(currentAttempt: number, options: AsyncRetryOptions): Promise<void> {
const { jitterIncrement = 500, jitterInterval = 100 } = options;
const maxWait = jitterIncrement > 1 ? jitterInterval + jitterIncrement : jitterInterval * (1 + jitterIncrement);
const waitTime = Math.min(jitterInterval, Math.random() * maxWait);
await sleep(waitTime);
},
async static(currentAttempt: number, options: AsyncRetryOptions): Promise<void> {
const { jitterInterval = 0 } = options;
await sleep(jitterInterval);
},
};
export default async function asyncRetry<T = unknown>(task: () => T | Promise<T>, options?: AsyncRetryOptions, currentAttempt = 1): Promise<T> {
const options_ = options || {};
const { maxAttempts = 3, jitterStrategy = "static" } = options_;
try {
await jitterStrategies[jitterStrategy](currentAttempt, options_);
return await task();
} catch (error) {
if (currentAttempt >= maxAttempts) {
if (Error.captureStackTrace) Error.captureStackTrace(error, asyncRetry);
throw error;
}
return asyncRetry<T>(task, options, currentAttempt + 1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment