UNPKG

@seriouslag/httpclient

Version:
76 lines (67 loc) 2.79 kB
import { Sleep } from '../utilities/sleep'; import { getIsSuccessfulHttpStatus } from '../utilities/getIsSuccessfulHttpStatus'; import { HttpRequestStrategy } from '../HttpRequestStrategies/HttpRequestStrategy'; import { Request, HttpResponse } from '../Adaptors'; export interface ExponentialBackoffOptions { /** Determines if the first request will be delayed */ delayFirstRequest?: boolean; /** The maximum number of retries to attempt, default is 5, set to 0 for indefinite retries */ maxRetryCount?: number; /** The base delay in milliseconds, will be used to calculate backoff */ baseDelay?: number; /** The maximum delay to use; set to -1 or undefined for no cap */ maxDelay?: number; /** The factor that will be used to grow the delay */ factor?: number; } /** Retries HTTP requests with a specified backoff strategy until the max retry count. */ export class ExponentialBackoffRequestStrategy implements HttpRequestStrategy { /** TOO MANY REQUESTS STATUS CODE */ private TOO_MANY_REQUESTS_STATUS = 429; private delayFirstRequest: boolean; private maxRetryCount: number; private baseDelay: number; private factor: number; private maxDelay: number; constructor(private options: ExponentialBackoffOptions = {}) { const { delayFirstRequest, maxRetryCount, baseDelay, factor, maxDelay } = this.options; this.delayFirstRequest = delayFirstRequest ?? false; this.maxRetryCount = maxRetryCount ?? 5; this.baseDelay = baseDelay ?? 100; this.factor = factor ?? 2; this.maxDelay = maxDelay ?? -1; } public async request<T = unknown>( request: Request<T>, ): Promise<HttpResponse<T>> { let response: HttpResponse<T>; let retryCount = 0; let isSuccessfulHttpStatus = false; let isTooManyRequests = false; let isAtRetryLimit = false; let delay = this.baseDelay; do { if (this.getShouldDelay(retryCount)) { await Sleep(delay); } retryCount += 1; response = await request.do(); isSuccessfulHttpStatus = getIsSuccessfulHttpStatus(response.status); isTooManyRequests = response.status === this.TOO_MANY_REQUESTS_STATUS; isAtRetryLimit = this.getIsAtRetryMax(retryCount); delay *= this.factor * retryCount; // set delay to max delay if delay is greater than max delay if (this.maxDelay > -1 && delay > this.maxDelay) { delay = this.maxDelay; } } while (!isSuccessfulHttpStatus && !isTooManyRequests && !isAtRetryLimit); return response; } private getIsAtRetryMax(retryCount: number): boolean { return this.maxRetryCount === 0 ? false : retryCount >= this.maxRetryCount; } private getShouldDelay(retryCount: number): boolean { return retryCount !== 0 || this.delayFirstRequest; } }