@openmrs/esm-utils
Version:
Helper utilities for OpenMRS
46 lines (45 loc) • 1.84 kB
JavaScript
/** @module @category Utility */ /**
* Options for configuring the behavior of the {@link retry} function.
*/ /**
* Executes the specified function and retries executing on failure with a custom backoff strategy
* defined by the options.
*
* If not configured otherwise, this function uses the following default options:
* * Retries 5 times beyond the initial attempt.
* * Uses an exponential backoff starting with an initial delay of 1000ms.
* @param fn The function to be executed and retried on failure.
* @param options Additional options which configure the retry behavior.
* @returns The result of successfully executing `fn`.
* @throws Rethrows the final error of running `fn` when the function stops retrying.
*/ export async function retry(fn, options = {}) {
let { shouldRetry, getDelay, onError } = options;
shouldRetry = shouldRetry ?? ((attempt)=>limitAttempts(attempt, 5));
getDelay = getDelay ?? ((attempt)=>getExponentialDelay(attempt, 1000));
let attempt = 0;
let lastError = undefined;
do {
try {
await delay(getDelay(attempt));
return await fn();
} catch (e) {
onError?.(e, attempt);
lastError = e;
}
}while (shouldRetry(attempt++))
// If we reach this fn errored and shouldn't retry anymore. Simply rethrow the final error as
// a means of ending the retry process without a result.
throw lastError;
}
function limitAttempts(attempt, maxAttempts) {
return attempt <= maxAttempts;
}
function getExponentialDelay(attempt, startingDelay, initialDelay = false) {
const exponent = initialDelay ? attempt + 1 : attempt;
return startingDelay * Math.pow(2, exponent);
}
async function delay(ms) {
if (ms <= 0) {
return;
}
return new Promise((res)=>setTimeout(res, ms));
}