import { HttpOperationResponse } from "../httpOperationResponse" ; import * as utils from "../util/utils" ; import { WebResourceLike } from "../webResource" ; import { BaseRequestPolicy , RequestPolicy , RequestPolicyFactory , RequestPolicyOptionsLike , } from "./requestPolicy" ; import { RestError } from "../restError" ; export interface RetryData { retryCount : number ; retryInterval : number ; error ? : RetryError ; } export interface RetryError extends Error { message : string ; code ? : string ; innerError ? : RetryError ; } export function exponentialRetryPolicy ( retryCount ? , retryInterval ? , minRetryInterval ? , maxRetryInterval ? ) { return { create : ( nextPolicy , options ) => { return new ExponentialRetryPolicy ( nextPolicy , options , retryCount , retryInterval , minRetryInterval , maxRetryInterval ) ; } , } ; } const DEFAULT_CLIENT_RETRY_INTERVAL = 1000 * 30 ; const DEFAULT_CLIENT_RETRY_COUNT = 3 ; const DEFAULT_CLIENT_MAX_RETRY_INTERVAL = 1000 * 90 ; const DEFAULT_CLIENT_MIN_RETRY_INTERVAL = 1000 * 3 ; class export class ExponentialRetryPolicy extends BaseRequestPolicy { /**
     * The client retry count.
     */ retryCount : number ; /**
     * The client retry interval in milliseconds.
     */ retryInterval : number ; /**
     * The minimum retry interval in milliseconds.
     */ minRetryInterval : number ; /**
     * The maximum retry interval in milliseconds.
     */ maxRetryInterval : number ; constructor param { RequestPolicy } nextPolicy param { RequestPolicyOptionsLike } options param { number } retryCount param { number } retryInterval param { number } minRetryInterval param { number } maxRetryInterval constructor ( nextPolicy , options , retryCount ? , retryInterval ? , minRetryInterval ? , maxRetryInterval ? ) { super ( nextPolicy , options ) ; function isNumber ( n ) { return typeof n === "number" ; } this . retryCount = isNumber ( retryCount ) ? retryCount : DEFAULT_CLIENT_RETRY_COUNT ; this . retryInterval = isNumber ( retryInterval ) ? retryInterval : DEFAULT_CLIENT_RETRY_INTERVAL ; this . minRetryInterval = isNumber ( minRetryInterval ) ? minRetryInterval : DEFAULT_CLIENT_MIN_RETRY_INTERVAL ; this . maxRetryInterval = isNumber ( maxRetryInterval ) ? maxRetryInterval : DEFAULT_CLIENT_MAX_RETRY_INTERVAL ; } public sendRequest ( request ) { return this . _nextPolicy . sendRequest ( request . clone ( ) ) . then ( ( response ) => retry ( this , request , response ) ) . catch ( ( error ) => retry ( this , request , error . response , undefined , error ) ) ; } } param { ExponentialRetryPolicy } policy param { number } statusCode param { RetryData } retryData return { boolean } function shouldRetry ( policy , statusCode , retryData ) { if ( statusCode == undefined || ( statusCode < 500 && statusCode !== 408 ) || statusCode === 501 || statusCode === 505 ) { return false ; } let currentCount ; if ( ! retryData ) { throw new Error ( "retryData for the ExponentialRetryPolicyFilter cannot be null." ) ; } else { currentCount = retryData && retryData . retryCount ; } return currentCount < policy . retryCount ; } param { ExponentialRetryPolicy } policy param { RetryData } retryData param { RetryError } 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 * 1.2 - policy . retryInterval * 0.8 ) ) ; incrementDelta *= boundedRandDelta ; retryData . retryInterval = Math . min ( policy . minRetryInterval + incrementDelta , policy . maxRetryInterval ) ; return retryData ; } function retry ( policy , request , response ? , retryData ? , requestError ? ) { retryData = updateRetryData ( policy , retryData , requestError ) ; const isAborted = request . abortSignal && request . abortSignal . aborted ; if ( ! isAborted && shouldRetry ( policy , response && response . status , retryData ) ) { return utils . delay ( retryData . retryInterval ) . then ( ( ) => policy . _nextPolicy . sendRequest ( request . clone ( ) ) ) . then ( ( res ) => retry ( policy , request , res , retryData , undefined ) ) . catch ( ( err ) => retry ( policy , request , response , retryData , err ) ) ; } else if ( isAborted || requestError || ! response ) { const err = retryData . error || new RestError ( "Failed to send the request." , RestError . REQUEST_SEND_ERROR , response && response . status , response && response . request , response ) ; return Promise . reject ( err ) ; } else { return Promise . resolve ( response ) ; } }