import { HttpOperationResponse } from "../httpOperationResponse" ; import * as utils from "../util/utils" ; import { WebResourceLike } from "../webResource" ; import { BaseRequestPolicy , RequestPolicy , RequestPolicyFactory , RequestPolicyOptionsLike , } from "./requestPolicy" ; export interface RetryData { retryCount : number ; retryInterval : number ; error ? : RetryError ; } export interface RetryError extends Error { message : string ; code ? : string ; innerError ? : RetryError ; } export function systemErrorRetryPolicy ( retryCount ? , retryInterval ? , minRetryInterval ? , maxRetryInterval ? ) { return { create : ( nextPolicy , options ) => { return new SystemErrorRetryPolicy ( nextPolicy , options , retryCount , retryInterval , minRetryInterval , maxRetryInterval ) ; } , } ; } class constructor param { number } retryCount param { number } retryInterval param { number } minRetryInterval param { number } maxRetryInterval export class SystemErrorRetryPolicy extends BaseRequestPolicy { retryCount : number ; retryInterval : number ; minRetryInterval : number ; maxRetryInterval : number ; DEFAULT_CLIENT_RETRY_INTERVAL = 1000 * 30 ; DEFAULT_CLIENT_RETRY_COUNT = 3 ; DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90 ; DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3 ; constructor ( nextPolicy , options , retryCount ? , retryInterval ? , minRetryInterval ? , maxRetryInterval ? ) { super ( nextPolicy , options ) ; this . retryCount = typeof retryCount === "number" ? retryCount : this . DEFAULT_CLIENT_RETRY_COUNT ; this . retryInterval = typeof retryInterval === "number" ? retryInterval : this . DEFAULT_CLIENT_RETRY_INTERVAL ; this . minRetryInterval = typeof minRetryInterval === "number" ? minRetryInterval : this . DEFAULT_CLIENT_MIN_RETRY_INTERVAL ; this . maxRetryInterval = typeof maxRetryInterval === "number" ? maxRetryInterval : this . DEFAULT_CLIENT_MAX_RETRY_INTERVAL ; } public sendRequest ( request ) { return this . _nextPolicy . sendRequest ( request . clone ( ) ) . catch ( ( error ) => retry ( this , request , error . response , error ) ) ; } } param { number } statusCode param { RetryData } retryData return { boolean } function shouldRetry ( policy , retryData ) { let currentCount ; if ( ! retryData ) { throw new Error ( "retryData for the SystemErrorRetryPolicyFilter cannot be null." ) ; } else { currentCount = retryData && retryData . retryCount ; } return currentCount < policy . retryCount ; } param { RetryData } retryData param { object } err function updateRetryData ( policy , retryData ? , err ? ) { if ( ! retryData ) { retryData = { retryCount : 0 , retryInterval : 0 , } ; } if ( err ) { if ( retryData . error ) { err . innerError = retryData . error ; } retryData . error = err ; } retryData . retryCount ++ ; let incrementDelta = Math . pow ( 2 , retryData . retryCount ) - 1 ; const boundedRandDelta = policy . retryInterval * 0.8 + Math . floor ( Math . random ( ) * ( policy . retryInterval * 0.4 ) ) ; incrementDelta *= boundedRandDelta ; retryData . retryInterval = Math . min ( policy . minRetryInterval + incrementDelta , policy . maxRetryInterval ) ; return retryData ; } async function retry ( policy , request , operationResponse , err ? , retryData ? ) { retryData = updateRetryData ( policy , retryData , err ) ; if ( err && err . code && shouldRetry ( policy , retryData ) && ( err . code === "ETIMEDOUT" || err . code === "ESOCKETTIMEDOUT" || err . code === "ECONNREFUSED" || err . code === "ECONNRESET" || err . code === "ENOENT" ) ) { try { await utils . delay ( retryData . retryInterval ) ; return policy . _nextPolicy . sendRequest ( request . clone ( ) ) ; } catch ( error ) { return retry ( policy , request , operationResponse , error , retryData ) ; } } else { if ( err ) { return Promise . reject ( retryData . error ) ; } return operationResponse ; } }