Skip to content

Commit

Permalink
Add retry delay
Browse files Browse the repository at this point in the history
  • Loading branch information
dhadka committed Aug 18, 2020
1 parent 1ef26b2 commit de52c86
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 11 deletions.
19 changes: 13 additions & 6 deletions packages/cache/__tests__/requestUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand All @@ -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
}
}
)
Expand All @@ -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)
}
Expand Down
3 changes: 3 additions & 0 deletions packages/cache/src/internal/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
19 changes: 14 additions & 5 deletions packages/cache/src/internal/requestUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
IHttpClientResponse,
ITypedResponse
} from '@actions/http-client/interfaces'
import {RetryDelay} from './constants'

export function isSuccessStatusCode(statusCode?: number): boolean {
if (!statusCode) {
Expand Down Expand Up @@ -31,11 +32,16 @@ export function isRetryableStatusCode(statusCode?: number): boolean {
return retryableStatusCodes.includes(statusCode)
}

async function sleep(milliseconds: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, milliseconds))
}

export async function retry<T>(
name: string,
method: () => Promise<T>,
getStatusCode: (arg0: T) => number | undefined,
maxAttempts = 2,
delay = RetryDelay,
onError: ((arg0: Error) => T | undefined) | undefined = undefined
): Promise<T> {
let errorMessage = ''
Expand Down Expand Up @@ -69,7 +75,7 @@ export async function retry<T>(
isRetryable = isRetryableStatusCode(statusCode)
errorMessage = `Cache service responded with ${statusCode}`
}

core.debug(
`${name} - Attempt ${attempt} of ${maxAttempts} failed with error: ${errorMessage}`
)
Expand All @@ -79,6 +85,7 @@ export async function retry<T>(
break
}

await sleep(delay)
attempt++
}

Expand All @@ -95,11 +102,12 @@ export async function retryTypedResponse<T>(
method,
(response: ITypedResponse<T>) => response.statusCode,
maxAttempts,
RetryDelay,
// 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
// casting Error object to any to workaround missing property errors.
// an ITypedResponse<T> 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'],
Expand All @@ -122,6 +130,7 @@ export async function retryHttpClientResponse<T>(
name,
method,
(response: IHttpClientResponse) => response.message.statusCode,
maxAttempts
maxAttempts,
RetryDelay
)
}

0 comments on commit de52c86

Please sign in to comment.