Skip to content

Instantly share code, notes, and snippets.

@Jarvis1010
Last active January 26, 2024 01:45
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Jarvis1010/0e84fca4a7f3a54b2ba1bcde2a67f79b to your computer and use it in GitHub Desktop.
Save Jarvis1010/0e84fca4a7f3a54b2ba1bcde2a67f79b to your computer and use it in GitHub Desktop.
retry
type PromiseFunc<T, K extends unknown = undefined[]> = (
...args: K
) => Promise<T>;
interface Config {
initialDelay?: number;
attempts?: number;
}
function waitFn<T>(fn: PromiseFunc<T>, time: number): Promise<T> {
return new Promise((r) =>
setTimeout(() => {
r(fn());
}, time)
);
}
/**
* Retries an async function n times with exponential backoff
* @param fn async function to retry
* @param options attempts: number of attempts defaults to 5, initialDelay: initial delay in ms defaults to 100
* @returns async function that retries the given function n times
*/
export default function withRetry<K extends unknown[], T = void>(
fn: PromiseFunc<T, K>,
options?: Config
): PromiseFunc<T, K> {
const { attempts = 5, initialDelay = 100 } = options ?? {};
const retries = Array.from(Array(attempts).keys()).map(
(x) => x ** 2 * (initialDelay || 1)
);
return (...args) =>
retries.reduce(
(promise, time) => promise.catch(() => waitFn(() => fn(...args), time)),
fn(...args)
);
}
//Example of use
async function identityOrFail<T>(b: T): Promise<T> {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (Math.random() > 0.5) {
resolve(b);
} else {
reject(new Error('failed'));
}
}, 1000);
});
}
const identityOrFailWithRetry = withRetry(identityOrFail, {initialDelay:300, attempts:20})
identityOrFailWithRetry(1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment