mirror of
https://git.mirrors.martin98.com/https://github.com/actions/toolkit
synced 2025-11-19 05:31:05 +08:00
* 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
80 lines
2.2 KiB
TypeScript
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)
|
|
}
|