export interface RetryPromiseOptions { param err param times onRejected ? : ( err : unknown , errorTimes : number ) => Promise < void > | void ; /**
     * retry interval in millisecond, defaults to 300ms
     */ onRejectedInterval ? : number ; maxRetryTimes ? : number ; } param timeout export function asyncSleep ( timeout ) { return new Promise ( ( resolve ) => setTimeout ( resolve , timeout ) ) ; } export class TooManyRetriesError extends Error { public raw : unknown ; constructor ( times , error ? ) { const sinceMessage = error instanceof Error ? error . message : String ( error || 'unknown error' ) ; super ( `Retried ${ times } times, too many retries, since: ${ sinceMessage }` ) ; this . raw = error ; } } param promiseThunk param options export async function retryPromise < T > ( promiseThunk , options = { } ) { let errorTimes = 0 ; const { onRejectedInterval = 300 , onRejected , maxRetryTimes = 5 } = options ; function internal ( ) { return promiseThunk ( ) . catch ( async ( err ) => { errorTimes ++ ; if ( onRejected ) await onRejected ( err , errorTimes ) ; if ( errorTimes <= maxRetryTimes ) return asyncSleep ( onRejectedInterval ) . then ( internal ) ; throw new TooManyRetriesError ( errorTimes , err ) ; } ) ; } return internal ( ) ; } interface ForeverPromiseOptions { onRejected ? : RetryPromiseOptions [ 'onRejected' ] ; onRejectedInterval : number ; onResolvedInterval : number ; } param promiseThunk param options export function foreverPromise ( promiseThunk , options ) { const { onRejectedInterval , onResolvedInterval , onRejected } = options ; void ( async ( ) => { for ( let times = 0 ; ; times ++ ) { await retryPromise ( ( ) => promiseThunk ( times ) , { maxRetryTimes : Infinity , onRejected : onRejected , onRejectedInterval : onRejectedInterval , } ) ; await asyncSleep ( onResolvedInterval ) ; } } ) ( ) ; }