Skip to content

Instantly share code, notes, and snippets.

@raynirola
Last active February 6, 2024 15:31
Show Gist options
  • Save raynirola/9e4e4770d16ac539e31564e456eb5aa0 to your computer and use it in GitHub Desktop.
Save raynirola/9e4e4770d16ac539e31564e456eb5aa0 to your computer and use it in GitHub Desktop.
Simple retry helper with typescript
type Args<T> = {
fn: () => Promise<T>;
retries: number;
delay: number;
backoffFactor: number;
onFailedAttempt?: (error: unknown, attemptNumber: number) => Promise<void>;
};
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
class RetryExhaustedError extends Error {
constructor() {
super("Retry attempts have been exhausted");
this.name = "RetryExhaustedError";
}
}
class OnFailedAttemptError extends Error {
constructor(error: unknown) {
super(
`Error in onFailedAttempt: ${
error instanceof Error ? error.message : "Unknown error"
}`
);
this.name = "OnFailedAttemptError";
}
}
async function retry<T>(
{
fn,
retries = 3,
delay = 1000,
backoffFactor = 2,
onFailedAttempt,
}: Args<T>,
attempt = 1
): Promise<T> {
try {
return await fn();
} catch (_aError) {
if (attempt > retries) throw new RetryExhaustedError();
try {
await onFailedAttempt?.(_aError, attempt);
} catch (_hError) {
throw new OnFailedAttemptError(_hError);
}
await sleep(delay * Math.pow(backoffFactor, attempt - 1));
return await retry(
{ fn, retries, delay, backoffFactor, onFailedAttempt },
attempt + 1
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment