-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core): make http client configurable and add retry support
Closes #31
- Loading branch information
Wajahat Iqbal
authored
Jan 3, 2022
1 parent
a3d0023
commit 07ff535
Showing
4 changed files
with
153 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { getHeader } from './httpHeaders'; | ||
import { HttpMethod } from './httpRequest'; | ||
|
||
/** | ||
* An interface for all configuration parameters needed for retrying in case of transient failures. | ||
*/ | ||
export interface RetryConfiguration { | ||
/** Maximum number of retries. */ | ||
maxNumberOfRetries: number; | ||
/** Whether to retry on request timeout. */ | ||
retryOnTimeout: boolean; | ||
/** | ||
* Interval before next retry. | ||
* Used in calculation of wait time for next request in case of failure. | ||
*/ | ||
retryInterval: number; | ||
/** Overall wait time for the requests getting retried. */ | ||
maximumRetryWaitTime: number; | ||
/** Used in calculation of wait time for next request in case of failure. */ | ||
backoffFactor: number; | ||
/** Http status codes to retry against. */ | ||
httpStatusCodesToRetry: number[]; | ||
/** Http status codes to retry against. */ | ||
httpMethodsToRetry: HttpMethod[]; | ||
} | ||
|
||
/** | ||
* Returns wait time for the request | ||
* @param retryConfig Configuration for retry | ||
* @param method HttpMethod of the request | ||
* @param allowedWaitTime Remaining allowed wait time | ||
* @param retryCount Retry attempt number | ||
* @param httpCode Status code received | ||
* @param headers Response headers | ||
* @param timeoutError Error from the server | ||
* @returns Wait time before the retry | ||
*/ | ||
export function getRetryWaitTime( | ||
retryConfig: RetryConfiguration, | ||
method: HttpMethod, | ||
allowedWaitTime: number, | ||
retryCount: number, | ||
httpCode?: number, | ||
headers?: Record<string, string>, | ||
timeoutError?: Error | ||
): number { | ||
let retryWaitTime = 0.0; | ||
let retry = false; | ||
let retryAfter = 0; | ||
if ( | ||
retryConfig.httpMethodsToRetry.includes(method) && | ||
retryCount < retryConfig.maxNumberOfRetries | ||
) { | ||
if (timeoutError) { | ||
retry = retryConfig.retryOnTimeout; | ||
} else if ( | ||
typeof headers !== 'undefined' && | ||
typeof httpCode !== 'undefined' | ||
) { | ||
retryAfter = getRetryAfterSeconds(getHeader(headers, 'retry-after')); | ||
retry = | ||
retryAfter > 0 || retryConfig.httpStatusCodesToRetry.includes(httpCode); | ||
} | ||
|
||
if (retry) { | ||
const noise = +(Math.random() / 100).toFixed(3); | ||
let waitTime = | ||
retryConfig.retryInterval * | ||
Math.pow(retryConfig.backoffFactor, retryCount) + | ||
noise; | ||
waitTime = Math.max(waitTime, retryAfter); | ||
if (waitTime <= allowedWaitTime) { | ||
retryWaitTime = waitTime; | ||
} | ||
} | ||
} | ||
return retryWaitTime; | ||
} | ||
|
||
function getRetryAfterSeconds(retryAfter: string | null): number { | ||
if (retryAfter == null) { | ||
return 0; | ||
} | ||
if (isNaN(+retryAfter)) { | ||
const timeDifference = (new Date(retryAfter).getTime() - Date.now()) / 1000; | ||
return isNaN(timeDifference) ? 0 : timeDifference; | ||
} | ||
return +retryAfter; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters