Konrad Pabjan c861dd8859
Retry all http calls for artifact upload and download (#675)
* Retry all http calls for artifact upload and download

* Extra debug information

* Fix lint

* Always read response body

* PR Feedback

* Change error message if patch call fails

* Add exponential backoff when retrying

* Rework tests and add diagnostic info if exception thrown

* Fix lint

* fix lint error for real this time

* PR cleanup

* 0.5.0 @actions/artifact release

* Display diagnostic info if non-retryable code is hit
2020-12-18 21:40:50 +01:00

80 lines
2.2 KiB
TypeScript

import {IHttpClientResponse} from '@actions/http-client/interfaces'
import {
isRetryableStatusCode,
isSuccessStatusCode,
sleep,
getExponentialRetryTimeInMilliseconds,
displayHttpDiagnostics
} from './utils'
import * as core from '@actions/core'
import {getRetryLimit} from './config-variables'
export async function retry(
name: string,
operation: () => Promise<IHttpClientResponse>,
customErrorMessages: Map<number, string>,
maxAttempts: number
): Promise<IHttpClientResponse> {
let response: IHttpClientResponse | undefined = undefined
let statusCode: number | undefined = undefined
let isRetryable = false
let errorMessage = ''
let customErrorInformation: string | undefined = undefined
let attempt = 1
while (attempt <= maxAttempts) {
try {
response = await operation()
statusCode = response.message.statusCode
if (isSuccessStatusCode(statusCode)) {
return response
}
// Extra error information that we want to display if a particular response code is hit
if (statusCode) {
customErrorInformation = customErrorMessages.get(statusCode)
}
isRetryable = isRetryableStatusCode(statusCode)
errorMessage = `Artifact service responded with ${statusCode}`
} catch (error) {
isRetryable = true
errorMessage = error.message
}
if (!isRetryable) {
core.info(`${name} - Error is not retryable`)
if (response) {
displayHttpDiagnostics(response)
}
break
}
core.info(
`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`
)
await sleep(getExponentialRetryTimeInMilliseconds(attempt))
attempt++
}
if (response) {
displayHttpDiagnostics(response)
}
if (customErrorInformation) {
throw Error(`${name} failed: ${customErrorInformation}`)
}
throw Error(`${name} failed: ${errorMessage}`)
}
export async function retryHttpClientRequest<T>(
name: string,
method: () => Promise<IHttpClientResponse>,
customErrorMessages: Map<number, string> = new Map(),
maxAttempts = getRetryLimit()
): Promise<IHttpClientResponse> {
return await retry(name, method, customErrorMessages, maxAttempts)
}