This commit applies `strictNullChecks` to the entire codebase to improve maintainability and type safety. Key changes include: - Remove some explicit null-checks where unnecessary. - Add necessary null-checks. - Refactor static factory functions for a more functional approach. - Improve some test names and contexts for better debugging. - Add unit tests for any additional logic introduced. - Refactor `createPositionFromRegexFullMatch` to its own function as the logic is reused. - Prefer `find` prefix on functions that may return `undefined` and `get` prefix for those that always return a value.
52 lines
1.7 KiB
TypeScript
52 lines
1.7 KiB
TypeScript
import { sleep } from '@/infrastructure/Threading/AsyncSleep';
|
|
import { IUrlStatus } from './IUrlStatus';
|
|
|
|
const DefaultBaseRetryIntervalInMs = 5 /* sec */ * 1000;
|
|
|
|
export async function retryWithExponentialBackOff(
|
|
action: () => Promise<IUrlStatus>,
|
|
baseRetryIntervalInMs: number = DefaultBaseRetryIntervalInMs,
|
|
currentRetry = 1,
|
|
): Promise<IUrlStatus> {
|
|
const maxTries = 3;
|
|
const status = await action();
|
|
if (shouldRetry(status)) {
|
|
if (currentRetry <= maxTries) {
|
|
const exponentialBackOffInMs = getRetryTimeoutInMs(currentRetry, baseRetryIntervalInMs);
|
|
// tslint:disable-next-line: no-console
|
|
console.log(`Retrying (${currentRetry}) in ${exponentialBackOffInMs / 1000} seconds`, status);
|
|
await sleep(exponentialBackOffInMs);
|
|
return retryWithExponentialBackOff(action, baseRetryIntervalInMs, currentRetry + 1);
|
|
}
|
|
}
|
|
return status;
|
|
}
|
|
|
|
function shouldRetry(status: IUrlStatus) {
|
|
if (status.error) {
|
|
return true;
|
|
}
|
|
if (status.code === undefined) {
|
|
return true;
|
|
}
|
|
return isTransientError(status.code)
|
|
|| status.code === 429; // Too Many Requests
|
|
}
|
|
|
|
function isTransientError(statusCode: number) {
|
|
return statusCode >= 500 && statusCode <= 599;
|
|
}
|
|
|
|
function getRetryTimeoutInMs(
|
|
currentRetry: number,
|
|
baseRetryIntervalInMs: number = DefaultBaseRetryIntervalInMs,
|
|
) {
|
|
const retryRandomFactor = 0.5; // Retry intervals are between 50% and 150%
|
|
// of the exponentially increasing base amount
|
|
const minRandom = 1 - retryRandomFactor;
|
|
const maxRandom = 1 + retryRandomFactor;
|
|
const randomization = (Math.random() * (maxRandom - minRandom)) + maxRandom;
|
|
const exponential = 2 ** (currentRetry - 1);
|
|
return Math.ceil(exponential * baseRetryIntervalInMs * randomization);
|
|
}
|