import { sleep } from '@/infrastructure/Threading/AsyncSleep' ; import { IUrlStatus } from './IUrlStatus' ; const DefaultBaseRetryIntervalInMs = 5 * 1000 ; export async function retryWithExponentialBackOff ( action , baseRetryIntervalInMs = DefaultBaseRetryIntervalInMs , currentRetry = 1 ) { const maxTries = 3 ; const status = await action ( ) ; if ( shouldRetry ( status ) ) { if ( currentRetry <= maxTries ) { const exponentialBackOffInMs = getRetryTimeoutInMs ( currentRetry , baseRetryIntervalInMs ) ; console . log ( `Retrying (${ currentRetry }) in ${ exponentialBackOffInMs / 1000 } seconds` , status ) ; await sleep ( exponentialBackOffInMs ) ; return retryWithExponentialBackOff ( action , baseRetryIntervalInMs , currentRetry + 1 ) ; } } return status ; } function shouldRetry ( status ) { if ( status . error ) { return true ; } return isTransientError ( status . code ) || status . code === 429 ; } function isTransientError ( statusCode ) { return statusCode >= 500 && statusCode <= 599 ; } function getRetryTimeoutInMs ( currentRetry , baseRetryIntervalInMs = DefaultBaseRetryIntervalInMs ) { const retryRandomFactor = 0.5 ; 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 ) ; }