diff --git a/packages/middleware-retry/src/configurations.ts b/packages/middleware-retry/src/configurations.ts index da81a5e46a4e..c0c7ddd8b492 100644 --- a/packages/middleware-retry/src/configurations.ts +++ b/packages/middleware-retry/src/configurations.ts @@ -3,26 +3,26 @@ import { ExponentialBackOffStrategy } from "./defaultStrategy"; export interface RetryInputConfig { /** - * The maximum number of times requests that encounter potentially transient failures should be retried + * The maximum number of times requests that encounter retryable failures should be attempted. */ - maxRetries?: number; + maxAttempts?: number; /** * The strategy to retry the request. Using built-in exponential backoff strategy by default. */ retryStrategy?: RetryStrategy; } export interface RetryResolvedConfig { - maxRetries: number; + maxAttempts: number; retryStrategy: RetryStrategy; } export function resolveRetryConfig( input: T & RetryInputConfig ): T & RetryResolvedConfig { - const maxRetries = input.maxRetries === undefined ? 3 : input.maxRetries; + const maxAttempts = input.maxAttempts === undefined ? 3 : input.maxAttempts; return { ...input, - maxRetries, + maxAttempts, retryStrategy: - input.retryStrategy || new ExponentialBackOffStrategy(maxRetries) + input.retryStrategy || new ExponentialBackOffStrategy(maxAttempts) }; } diff --git a/packages/middleware-retry/src/defaultStrategy.ts b/packages/middleware-retry/src/defaultStrategy.ts index bb7d41a21960..ad95c87c462c 100644 --- a/packages/middleware-retry/src/defaultStrategy.ts +++ b/packages/middleware-retry/src/defaultStrategy.ts @@ -35,34 +35,35 @@ export interface DelayDecider { export class ExponentialBackOffStrategy implements RetryStrategy { constructor( - public readonly maxRetries: number, + public readonly maxAttempts: number, private retryDecider: RetryDecider = defaultRetryDecider, private delayDecider: DelayDecider = defaultDelayDecider ) {} - private shouldRetry(error: SdkError, retryAttempted: number) { - return retryAttempted < this.maxRetries && this.retryDecider(error); + private shouldRetry(error: SdkError, attempts: number) { + return attempts < this.maxAttempts && this.retryDecider(error); } async retry( next: FinalizeHandler, args: FinalizeHandlerArguments ) { - let retries = 0; + let attempts = 0; let totalDelay = 0; while (true) { try { const { response, output } = await next(args); - output.$metadata.retries = retries; + output.$metadata.attempts = attempts + 1; output.$metadata.totalRetryDelay = totalDelay; return { response, output }; } catch (err) { - if (this.shouldRetry(err as SdkError, retries)) { + attempts++; + if (this.shouldRetry(err as SdkError, attempts)) { const delay = this.delayDecider( isThrottlingError(err) ? THROTTLING_RETRY_DELAY_BASE : DEFAULT_RETRY_DELAY_BASE, - retries++ + attempts ); totalDelay += delay; @@ -74,7 +75,7 @@ export class ExponentialBackOffStrategy implements RetryStrategy { err.$metadata = {}; } - err.$metadata.retries = retries; + err.$metadata.attempts = attempts; err.$metadata.totalRetryDelay = totalDelay; throw err; } diff --git a/packages/middleware-retry/src/index.spec.ts b/packages/middleware-retry/src/index.spec.ts index f3863aec5987..8762f29b941d 100644 --- a/packages/middleware-retry/src/index.spec.ts +++ b/packages/middleware-retry/src/index.spec.ts @@ -12,25 +12,25 @@ import { SdkError } from "@aws-sdk/smithy-client"; describe("retryMiddleware", () => { it("should not retry when the handler completes successfully", async () => { const next = jest.fn().mockResolvedValue({ output: { $metadata: {} } }); - const retryHandler = retryMiddleware(resolveRetryConfig({ maxRetries: 0 }))( - next - ); + const retryHandler = retryMiddleware( + resolveRetryConfig({ maxAttempts: 0 }) + )(next); const { output: { $metadata } } = await retryHandler({ input: {}, request: new HttpRequest({}) }); - expect($metadata.retries).toBe(0); + expect($metadata.attempts).toBe(1); expect($metadata.totalRetryDelay).toBe(0); expect(next.mock.calls.length).toBe(1); }); it("should stop retrying when the the maximum number of retries is reached", async () => { - const maxRetries = 3; + const maxAttempts = 3; const error = new Error(); error.name = "ProvisionedThroughputExceededException"; const next = jest.fn().mockRejectedValue(error); - const retryHandler = retryMiddleware(resolveRetryConfig({ maxRetries }))( + const retryHandler = retryMiddleware(resolveRetryConfig({ maxAttempts }))( next ); @@ -38,16 +38,16 @@ describe("retryMiddleware", () => { retryHandler({ input: {}, request: new HttpRequest({}) }) ).rejects.toMatchObject(error); - expect(next.mock.calls.length).toBe(maxRetries + 1); + expect(next.mock.calls.length).toBe(maxAttempts); }); it("should not retry if the error is not transient", async () => { const error = new Error(); error.name = "ValidationException"; const next = jest.fn().mockRejectedValue(error); - const retryHandler = retryMiddleware(resolveRetryConfig({ maxRetries: 3 }))( - next - ); + const retryHandler = retryMiddleware( + resolveRetryConfig({ maxAttempts: 3 }) + )(next); await expect( retryHandler({ input: {}, request: new HttpRequest({}) }) @@ -69,15 +69,15 @@ describe("retryMiddleware", () => { jest.mock("./delayDecider"); - const maxRetries = 3; + const maxAttempts = 3; const delayDeciderMock = jest.spyOn( delayDeciderModule, "defaultDelayDecider" ); const retryDecider: RetryDecider = (error: SdkError) => true; - const strategy = new ExponentialBackOffStrategy(maxRetries, retryDecider); + const strategy = new ExponentialBackOffStrategy(maxAttempts, retryDecider); const retryHandler = retryMiddleware({ - maxRetries, + maxAttempts, retryStrategy: strategy })(next); @@ -85,8 +85,8 @@ describe("retryMiddleware", () => { expect(next.mock.calls.length).toBe(3); expect(delayDeciderMock.mock.calls).toEqual([ - [DEFAULT_RETRY_DELAY_BASE, 0], - [THROTTLING_RETRY_DELAY_BASE, 1] + [DEFAULT_RETRY_DELAY_BASE, 1], + [THROTTLING_RETRY_DELAY_BASE, 2] ]); }); }); diff --git a/packages/middleware-retry/src/retryMiddleware.ts b/packages/middleware-retry/src/retryMiddleware.ts index 33ded6cd0d66..2bc454e80506 100644 --- a/packages/middleware-retry/src/retryMiddleware.ts +++ b/packages/middleware-retry/src/retryMiddleware.ts @@ -31,7 +31,7 @@ export const getRetryPlugin = ( options: RetryResolvedConfig ): Pluggable => ({ applyToStack: clientStack => { - if (options.maxRetries > 0) { + if (options.maxAttempts > 1) { clientStack.add(retryMiddleware(options), retryMiddlewareOptions); } } diff --git a/packages/types/src/response.ts b/packages/types/src/response.ts index 3bcbb9759a79..4ab0525c63f0 100644 --- a/packages/types/src/response.ts +++ b/packages/types/src/response.ts @@ -28,9 +28,9 @@ export interface ResponseMetadata { cfId?: string; /** - * The number of times this operation was retried. + * The number of times this operation was attempted. */ - retries?: number; + attempts?: number; /** * The total amount of time (in milliseconds) that was spent waiting between diff --git a/packages/types/src/util.ts b/packages/types/src/util.ts index 92083efb2973..83512cdea706 100644 --- a/packages/types/src/util.ts +++ b/packages/types/src/util.ts @@ -61,7 +61,7 @@ export interface RetryStrategy { * the maximum number of times requests that encounter potentially * transient failures should be retried */ - maxRetries: number; + maxAttempts: number; /** * the retry behavior the will invoke the next handler and handle the retry accordingly. * This function should also update the $metadata from the response accordingly.