diff --git a/packages/cache/__tests__/requestUtils.test.ts b/packages/cache/__tests__/requestUtils.test.ts index 0d78320d..1a4456fc 100644 --- a/packages/cache/__tests__/requestUtils.test.ts +++ b/packages/cache/__tests__/requestUtils.test.ts @@ -20,7 +20,8 @@ async function handleResponse( if (response.statusCode >= 900) { throw Error('Test Error') } 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 throw error } else { @@ -37,7 +38,9 @@ async function testRetryExpectingResult( const actualResult = await retry( 'test', async () => handleResponse(responses.pop()), - (response: TestResponse) => response.statusCode + (response: TestResponse) => response.statusCode, + 2, // maxAttempts + 0 // delay ) expect(actualResult.result).toEqual(expectedResult) @@ -54,12 +57,14 @@ async function testRetryConvertingErrorToResult( 'test', async () => handleResponse(responses.pop()), (response: TestResponse) => response.statusCode, - 2, + 2, // maxAttempts + 0, // delay (e: Error) => { - const error: any = e + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const error = e as any return { statusCode: error['statusCode'], - result: error['result'] + result: error['result'] ?? null } } ) @@ -77,7 +82,9 @@ async function testRetryExpectingError( retry( 'test', async () => handleResponse(responses.pop()), - (response: TestResponse) => response.statusCode + (response: TestResponse) => response.statusCode, + 2, // maxAttempts, + 0 // delay ) ).rejects.toBeInstanceOf(Error) } diff --git a/packages/cache/src/internal/constants.ts b/packages/cache/src/internal/constants.ts index 06c8c8f0..8a3125d1 100644 --- a/packages/cache/src/internal/constants.ts +++ b/packages/cache/src/internal/constants.ts @@ -11,6 +11,9 @@ export enum CompressionMethod { 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 // over the socket during this period, the socket is destroyed and the download // is aborted. diff --git a/packages/cache/src/internal/requestUtils.ts b/packages/cache/src/internal/requestUtils.ts index d489458b..14368da0 100644 --- a/packages/cache/src/internal/requestUtils.ts +++ b/packages/cache/src/internal/requestUtils.ts @@ -4,6 +4,7 @@ import { IHttpClientResponse, ITypedResponse } from '@actions/http-client/interfaces' +import {RetryDelay} from './constants' export function isSuccessStatusCode(statusCode?: number): boolean { if (!statusCode) { @@ -31,11 +32,16 @@ export function isRetryableStatusCode(statusCode?: number): boolean { return retryableStatusCodes.includes(statusCode) } +async function sleep(milliseconds: number): Promise { + return new Promise(resolve => setTimeout(resolve, milliseconds)) +} + export async function retry( name: string, method: () => Promise, getStatusCode: (arg0: T) => number | undefined, maxAttempts = 2, + delay = RetryDelay, onError: ((arg0: Error) => T | undefined) | undefined = undefined ): Promise { let errorMessage = '' @@ -69,7 +75,7 @@ export async function retry( isRetryable = isRetryableStatusCode(statusCode) errorMessage = `Cache service responded with ${statusCode}` } - + core.debug( `${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}` ) @@ -79,6 +85,7 @@ export async function retry( break } + await sleep(delay) attempt++ } @@ -95,11 +102,12 @@ export async function retryTypedResponse( method, (response: ITypedResponse) => response.statusCode, maxAttempts, + RetryDelay, // If the error object contains the statusCode property, extract it and return - // an ITypedResponse so it can be processed by the retry logic. Explicitly - // casting Error object to any to workaround missing property errors. + // an ITypedResponse so it can be processed by the retry logic. (e: Error) => { - const error : any = e + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const error = e as any if (error['statusCode']) { return { statusCode: error['statusCode'], @@ -122,6 +130,7 @@ export async function retryHttpClientResponse( name, method, (response: IHttpClientResponse) => response.message.statusCode, - maxAttempts + maxAttempts, + RetryDelay ) }