import { Clock , SystemClock , Time } from "./clock" ; export interface RetryStrategy < T , U > { retryUntil ( fn , predicate , onTimeout , timeout ) : Promise < T | U > ; } abstract class AbstractRetryStrategy < T , U > implements RetryStrategy < T , U > { protected constructor ( protected readonly clock = new SystemClock ( ) ) { } public abstract retryUntil ( fn , predicate , onTimeout , timeout ) ; protected hasTimedOut ( timeout , startTime ) { return this . clock . getTime ( ) - startTime > timeout ; } protected wait ( duration ) { return new Promise ( ( resolve ) => setTimeout ( resolve , duration ) ) ; } } export class IntervalRetryStrategy < T , U > extends AbstractRetryStrategy < T , U > { constructor ( private readonly interval ) { super ( ) ; } public async retryUntil ( fn , predicate , onTimeout , timeout ) { const startTime = this . clock . getTime ( ) ; let result = await fn ( ) ; while ( ! predicate ( result ) ) { if ( this . hasTimedOut ( timeout , startTime ) ) { return onTimeout ( ) ; } await this . wait ( this . interval ) ; result = await fn ( ) ; } return result ; } }