mirror of https://github.com/actions/toolkit
Add retry delay
parent
1ef26b2390
commit
de52c861c1
|
@ -20,7 +20,8 @@ async function handleResponse(
|
||||||
if (response.statusCode >= 900) {
|
if (response.statusCode >= 900) {
|
||||||
throw Error('Test Error')
|
throw Error('Test Error')
|
||||||
} else if (response.statusCode >= 600) {
|
} else if (response.statusCode >= 600) {
|
||||||
const error: any = Error('Test Error with Status Code')
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const error = Error('Test Error with Status Code') as any
|
||||||
error['statusCode'] = response.statusCode - 300
|
error['statusCode'] = response.statusCode - 300
|
||||||
throw error
|
throw error
|
||||||
} else {
|
} else {
|
||||||
|
@ -37,7 +38,9 @@ async function testRetryExpectingResult(
|
||||||
const actualResult = await retry(
|
const actualResult = await retry(
|
||||||
'test',
|
'test',
|
||||||
async () => handleResponse(responses.pop()),
|
async () => handleResponse(responses.pop()),
|
||||||
(response: TestResponse) => response.statusCode
|
(response: TestResponse) => response.statusCode,
|
||||||
|
2, // maxAttempts
|
||||||
|
0 // delay
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(actualResult.result).toEqual(expectedResult)
|
expect(actualResult.result).toEqual(expectedResult)
|
||||||
|
@ -54,12 +57,14 @@ async function testRetryConvertingErrorToResult(
|
||||||
'test',
|
'test',
|
||||||
async () => handleResponse(responses.pop()),
|
async () => handleResponse(responses.pop()),
|
||||||
(response: TestResponse) => response.statusCode,
|
(response: TestResponse) => response.statusCode,
|
||||||
2,
|
2, // maxAttempts
|
||||||
|
0, // delay
|
||||||
(e: Error) => {
|
(e: Error) => {
|
||||||
const error: any = e
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const error = e as any
|
||||||
return {
|
return {
|
||||||
statusCode: error['statusCode'],
|
statusCode: error['statusCode'],
|
||||||
result: error['result']
|
result: error['result'] ?? null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -77,7 +82,9 @@ async function testRetryExpectingError(
|
||||||
retry(
|
retry(
|
||||||
'test',
|
'test',
|
||||||
async () => handleResponse(responses.pop()),
|
async () => handleResponse(responses.pop()),
|
||||||
(response: TestResponse) => response.statusCode
|
(response: TestResponse) => response.statusCode,
|
||||||
|
2, // maxAttempts,
|
||||||
|
0 // delay
|
||||||
)
|
)
|
||||||
).rejects.toBeInstanceOf(Error)
|
).rejects.toBeInstanceOf(Error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,9 @@ export enum CompressionMethod {
|
||||||
Zstd = 'zstd'
|
Zstd = 'zstd'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The default delay in milliseconds between retry attempts.
|
||||||
|
export const RetryDelay = 5000
|
||||||
|
|
||||||
// Socket timeout in milliseconds during download. If no traffic is received
|
// Socket timeout in milliseconds during download. If no traffic is received
|
||||||
// over the socket during this period, the socket is destroyed and the download
|
// over the socket during this period, the socket is destroyed and the download
|
||||||
// is aborted.
|
// is aborted.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
IHttpClientResponse,
|
IHttpClientResponse,
|
||||||
ITypedResponse
|
ITypedResponse
|
||||||
} from '@actions/http-client/interfaces'
|
} from '@actions/http-client/interfaces'
|
||||||
|
import {RetryDelay} from './constants'
|
||||||
|
|
||||||
export function isSuccessStatusCode(statusCode?: number): boolean {
|
export function isSuccessStatusCode(statusCode?: number): boolean {
|
||||||
if (!statusCode) {
|
if (!statusCode) {
|
||||||
|
@ -31,11 +32,16 @@ export function isRetryableStatusCode(statusCode?: number): boolean {
|
||||||
return retryableStatusCodes.includes(statusCode)
|
return retryableStatusCodes.includes(statusCode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function sleep(milliseconds: number): Promise<void> {
|
||||||
|
return new Promise(resolve => setTimeout(resolve, milliseconds))
|
||||||
|
}
|
||||||
|
|
||||||
export async function retry<T>(
|
export async function retry<T>(
|
||||||
name: string,
|
name: string,
|
||||||
method: () => Promise<T>,
|
method: () => Promise<T>,
|
||||||
getStatusCode: (arg0: T) => number | undefined,
|
getStatusCode: (arg0: T) => number | undefined,
|
||||||
maxAttempts = 2,
|
maxAttempts = 2,
|
||||||
|
delay = RetryDelay,
|
||||||
onError: ((arg0: Error) => T | undefined) | undefined = undefined
|
onError: ((arg0: Error) => T | undefined) | undefined = undefined
|
||||||
): Promise<T> {
|
): Promise<T> {
|
||||||
let errorMessage = ''
|
let errorMessage = ''
|
||||||
|
@ -69,7 +75,7 @@ export async function retry<T>(
|
||||||
isRetryable = isRetryableStatusCode(statusCode)
|
isRetryable = isRetryableStatusCode(statusCode)
|
||||||
errorMessage = `Cache service responded with ${statusCode}`
|
errorMessage = `Cache service responded with ${statusCode}`
|
||||||
}
|
}
|
||||||
|
|
||||||
core.debug(
|
core.debug(
|
||||||
`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`
|
`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`
|
||||||
)
|
)
|
||||||
|
@ -79,6 +85,7 @@ export async function retry<T>(
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await sleep(delay)
|
||||||
attempt++
|
attempt++
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,11 +102,12 @@ export async function retryTypedResponse<T>(
|
||||||
method,
|
method,
|
||||||
(response: ITypedResponse<T>) => response.statusCode,
|
(response: ITypedResponse<T>) => response.statusCode,
|
||||||
maxAttempts,
|
maxAttempts,
|
||||||
|
RetryDelay,
|
||||||
// If the error object contains the statusCode property, extract it and return
|
// If the error object contains the statusCode property, extract it and return
|
||||||
// an ITypedResponse<T> so it can be processed by the retry logic. Explicitly
|
// an ITypedResponse<T> so it can be processed by the retry logic.
|
||||||
// casting Error object to any to workaround missing property errors.
|
|
||||||
(e: Error) => {
|
(e: Error) => {
|
||||||
const error : any = e
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const error = e as any
|
||||||
if (error['statusCode']) {
|
if (error['statusCode']) {
|
||||||
return {
|
return {
|
||||||
statusCode: error['statusCode'],
|
statusCode: error['statusCode'],
|
||||||
|
@ -122,6 +130,7 @@ export async function retryHttpClientResponse<T>(
|
||||||
name,
|
name,
|
||||||
method,
|
method,
|
||||||
(response: IHttpClientResponse) => response.message.statusCode,
|
(response: IHttpClientResponse) => response.message.statusCode,
|
||||||
maxAttempts
|
maxAttempts,
|
||||||
|
RetryDelay
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue