From a7466a7d378aef12d0a7062c288b043aa9eb5cfb Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Tue, 2 Jun 2020 23:44:48 +0000 Subject: [PATCH 1/8] chore: added SmithyException to SdkError --- packages/types/package.json | 3 +++ packages/types/src/util.ts | 3 ++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/types/package.json b/packages/types/package.json index 426a97843fb8..5fa87f9cf883 100755 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -4,6 +4,9 @@ "main": "./build/index.js", "types": "./build/index.d.ts", "description": "Types for the AWS SDK", + "dependencies": { + "@aws-sdk/smithy-client": "1.0.0-gamma.1" + }, "devDependencies": { "typescript": "~3.8.3" }, diff --git a/packages/types/src/util.ts b/packages/types/src/util.ts index 424ed53f42e9..a19eaeb1e900 100644 --- a/packages/types/src/util.ts +++ b/packages/types/src/util.ts @@ -5,6 +5,7 @@ import { FinalizeHandlerOutput } from "./middleware"; import { MetadataBearer } from "./response"; +import { SmithyException } from "@aws-sdk/smithy-client"; /** * A function that, given a TypedArray of bytes, can produce a string @@ -54,7 +55,7 @@ export interface BodyLengthCalculator { } // TODO Unify with the types created for the error parsers -export type SdkError = Error & MetadataBearer; +export type SdkError = Error & SmithyException & MetadataBearer; /** * Interface that specifies the retry behavior From ac9874106ece20fad5652f387e2d966a0e2ce0bc Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Tue, 2 Jun 2020 23:54:14 +0000 Subject: [PATCH 2/8] chore: add RetryableTrait to SmithyException --- packages/smithy-client/src/exception.ts | 7 +++++++ packages/smithy-client/src/index.ts | 1 + packages/smithy-client/src/retryable-trait.ts | 10 ++++++++++ 3 files changed, 18 insertions(+) create mode 100644 packages/smithy-client/src/retryable-trait.ts diff --git a/packages/smithy-client/src/exception.ts b/packages/smithy-client/src/exception.ts index 0e1fdccfaf4b..54aca7d77e2d 100644 --- a/packages/smithy-client/src/exception.ts +++ b/packages/smithy-client/src/exception.ts @@ -1,3 +1,5 @@ +import { RetryableTrait } from "./retryable-trait"; + /** * Type that is implemented by all Smithy shapes marked with the * error trait. @@ -17,4 +19,9 @@ export interface SmithyException { * The service that encountered the exception. */ readonly $service?: string; + + /** + * Indicates that an error MAY be retried by the client. + */ + readonly $retryable?: RetryableTrait; } diff --git a/packages/smithy-client/src/index.ts b/packages/smithy-client/src/index.ts index 5c6b196fae9f..39e3c29e567d 100644 --- a/packages/smithy-client/src/index.ts +++ b/packages/smithy-client/src/index.ts @@ -10,3 +10,4 @@ export * from "./lazy-json"; export * from "./date-utils"; export * from "./split-every"; export * from "./constants"; +export * from "./retryable-trait"; diff --git a/packages/smithy-client/src/retryable-trait.ts b/packages/smithy-client/src/retryable-trait.ts new file mode 100644 index 000000000000..6bbd5b054313 --- /dev/null +++ b/packages/smithy-client/src/retryable-trait.ts @@ -0,0 +1,10 @@ +/** + * A structure shape with the error trait. + * https://awslabs.github.io/smithy/spec/core.html#retryable-trait + */ +export interface RetryableTrait { + /** + * Indicates that the error is a retryable throttling error. + */ + readonly throttling?: boolean; +} From 0117771fb63bb7a77f1b7dc40ded3a45a95b5702 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 3 Jun 2020 15:08:31 +0000 Subject: [PATCH 3/8] fix: moved SdkError to @aws-sdk/smithy-client bec of dependency cycle erna WARN ECYCLE Dependency cycles detected, you should fix these! lerna WARN ECYCLE @aws-sdk/types -> @aws-sdk/smithy-client -> @aws-sdk/types lerna WARN ECYCLE @aws-sdk/middleware-stack -> (nested cycle: @aws-sdk/types -> @aws-sdk/smithy-client -> @aws-sdk/types) -> @aws-sdk/middleware-stack lerna WARN ECYCLE (nested cycle: @aws-sdk/middleware-stack -> (nested cycle: @aws-sdk/types -> @aws-sdk/smithy-client -> @aws-sdk/types) -> @aws-sdk/middleware-stack) -> (nested cycle: @aws-sdk/middleware-stack -> (nested cycle: @aws-sdk/types -> @aws-sdk/smithy-client -> @aws-sdk/types) -> @aws-sdk/middleware-stack) --- packages/middleware-retry/package.json | 1 + packages/middleware-retry/src/defaultStrategy.ts | 2 +- packages/middleware-retry/src/index.spec.ts | 2 +- packages/middleware-retry/src/retryDecider.spec.ts | 4 +++- packages/middleware-retry/src/retryDecider.ts | 2 +- packages/service-error-classification/package.json | 2 +- packages/service-error-classification/src/index.spec.ts | 4 ++-- packages/service-error-classification/src/index.ts | 2 +- packages/smithy-client/src/index.ts | 1 + packages/smithy-client/src/sdk-error.ts | 4 ++++ packages/types/package.json | 3 --- packages/types/src/util.ts | 4 ---- 12 files changed, 16 insertions(+), 15 deletions(-) create mode 100644 packages/smithy-client/src/sdk-error.ts diff --git a/packages/middleware-retry/package.json b/packages/middleware-retry/package.json index f85da2b149e6..a4bd3a6e5fd0 100644 --- a/packages/middleware-retry/package.json +++ b/packages/middleware-retry/package.json @@ -15,6 +15,7 @@ "license": "Apache-2.0", "dependencies": { "@aws-sdk/service-error-classification": "1.0.0-gamma.1", + "@aws-sdk/smithy-client": "1.0.0-gamma.1", "@aws-sdk/types": "1.0.0-gamma.1", "tslib": "^1.8.0" }, diff --git a/packages/middleware-retry/src/defaultStrategy.ts b/packages/middleware-retry/src/defaultStrategy.ts index bef7e1479a20..bb7d41a21960 100644 --- a/packages/middleware-retry/src/defaultStrategy.ts +++ b/packages/middleware-retry/src/defaultStrategy.ts @@ -5,8 +5,8 @@ import { import { defaultDelayDecider } from "./delayDecider"; import { defaultRetryDecider } from "./retryDecider"; import { isThrottlingError } from "@aws-sdk/service-error-classification"; +import { SdkError } from "@aws-sdk/smithy-client"; import { - SdkError, FinalizeHandler, MetadataBearer, FinalizeHandlerArguments, diff --git a/packages/middleware-retry/src/index.spec.ts b/packages/middleware-retry/src/index.spec.ts index b21b37aaa879..f3863aec5987 100644 --- a/packages/middleware-retry/src/index.spec.ts +++ b/packages/middleware-retry/src/index.spec.ts @@ -7,7 +7,7 @@ import { resolveRetryConfig } from "./configurations"; import * as delayDeciderModule from "./delayDecider"; import { ExponentialBackOffStrategy, RetryDecider } from "./defaultStrategy"; import { HttpRequest } from "@aws-sdk/protocol-http"; -import { SdkError } from "@aws-sdk/types"; +import { SdkError } from "@aws-sdk/smithy-client"; describe("retryMiddleware", () => { it("should not retry when the handler completes successfully", async () => { diff --git a/packages/middleware-retry/src/retryDecider.spec.ts b/packages/middleware-retry/src/retryDecider.spec.ts index 9ff61d463426..7c4e7d1d9d63 100644 --- a/packages/middleware-retry/src/retryDecider.spec.ts +++ b/packages/middleware-retry/src/retryDecider.spec.ts @@ -4,6 +4,7 @@ import { isTransientError } from "@aws-sdk/service-error-classification"; import { defaultRetryDecider } from "./retryDecider"; +import { SdkError } from "@aws-sdk/smithy-client"; jest.mock("@aws-sdk/service-error-classification", () => ({ isClockSkewError: jest.fn().mockReturnValue(false), @@ -12,7 +13,8 @@ jest.mock("@aws-sdk/service-error-classification", () => ({ })); describe("defaultRetryDecider", () => { - const createMockError = () => Object.assign(new Error(), { $metadata: {} }); + const createMockError = () => + Object.assign(new Error(), { $metadata: {} }) as SdkError; beforeEach(() => { jest.clearAllMocks(); diff --git a/packages/middleware-retry/src/retryDecider.ts b/packages/middleware-retry/src/retryDecider.ts index 7a7e0b32ad36..192c92ce8ed0 100644 --- a/packages/middleware-retry/src/retryDecider.ts +++ b/packages/middleware-retry/src/retryDecider.ts @@ -3,7 +3,7 @@ import { isThrottlingError, isTransientError } from "@aws-sdk/service-error-classification"; -import { SdkError } from "@aws-sdk/types"; +import { SdkError } from "@aws-sdk/smithy-client"; export const defaultRetryDecider = (error: SdkError) => { if (!error) { diff --git a/packages/service-error-classification/package.json b/packages/service-error-classification/package.json index 555178ebb01d..a6f9e649a530 100644 --- a/packages/service-error-classification/package.json +++ b/packages/service-error-classification/package.json @@ -14,7 +14,7 @@ }, "license": "Apache-2.0", "dependencies": { - "@aws-sdk/types": "1.0.0-gamma.1" + "@aws-sdk/smithy-client": "1.0.0-gamma.1" }, "devDependencies": { "@types/jest": "^25.1.4", diff --git a/packages/service-error-classification/src/index.spec.ts b/packages/service-error-classification/src/index.spec.ts index a7c6ac627078..159d9ff5bace 100644 --- a/packages/service-error-classification/src/index.spec.ts +++ b/packages/service-error-classification/src/index.spec.ts @@ -5,7 +5,7 @@ import { TRANSIENT_ERROR_STATUS_CODES } from "./constants"; import { isClockSkewError, isThrottlingError, isTransientError } from "./index"; -import { SdkError } from "@aws-sdk/types"; +import { SdkError } from "@aws-sdk/smithy-client"; const checkForErrorType = ( isErrorTypeFunc: (error: SdkError) => boolean, @@ -17,7 +17,7 @@ const checkForErrorType = ( name, $metadata: { httpStatusCode } }); - expect(isErrorTypeFunc(error)).toBe(errorTypeResult); + expect(isErrorTypeFunc(error as SdkError)).toBe(errorTypeResult); }; describe("isClockSkewError", () => { diff --git a/packages/service-error-classification/src/index.ts b/packages/service-error-classification/src/index.ts index 04581cf5d7b0..4c6844a45a64 100644 --- a/packages/service-error-classification/src/index.ts +++ b/packages/service-error-classification/src/index.ts @@ -4,7 +4,7 @@ import { TRANSIENT_ERROR_CODES, TRANSIENT_ERROR_STATUS_CODES } from "./constants"; -import { SdkError } from "@aws-sdk/types"; +import { SdkError } from "@aws-sdk/smithy-client"; export const isClockSkewError = (error: SdkError) => CLOCK_SKEW_ERROR_CODES.includes(error.name); diff --git a/packages/smithy-client/src/index.ts b/packages/smithy-client/src/index.ts index 39e3c29e567d..c3c1de955ce4 100644 --- a/packages/smithy-client/src/index.ts +++ b/packages/smithy-client/src/index.ts @@ -11,3 +11,4 @@ export * from "./date-utils"; export * from "./split-every"; export * from "./constants"; export * from "./retryable-trait"; +export * from "./sdk-error"; diff --git a/packages/smithy-client/src/sdk-error.ts b/packages/smithy-client/src/sdk-error.ts new file mode 100644 index 000000000000..18256727b737 --- /dev/null +++ b/packages/smithy-client/src/sdk-error.ts @@ -0,0 +1,4 @@ +import { SmithyException } from "./exception"; +import { MetadataBearer } from "@aws-sdk/types"; + +export type SdkError = Error & SmithyException & MetadataBearer; diff --git a/packages/types/package.json b/packages/types/package.json index 5fa87f9cf883..426a97843fb8 100755 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -4,9 +4,6 @@ "main": "./build/index.js", "types": "./build/index.d.ts", "description": "Types for the AWS SDK", - "dependencies": { - "@aws-sdk/smithy-client": "1.0.0-gamma.1" - }, "devDependencies": { "typescript": "~3.8.3" }, diff --git a/packages/types/src/util.ts b/packages/types/src/util.ts index a19eaeb1e900..92083efb2973 100644 --- a/packages/types/src/util.ts +++ b/packages/types/src/util.ts @@ -5,7 +5,6 @@ import { FinalizeHandlerOutput } from "./middleware"; import { MetadataBearer } from "./response"; -import { SmithyException } from "@aws-sdk/smithy-client"; /** * A function that, given a TypedArray of bytes, can produce a string @@ -54,9 +53,6 @@ export interface BodyLengthCalculator { (body: any): number | undefined; } -// TODO Unify with the types created for the error parsers -export type SdkError = Error & SmithyException & MetadataBearer; - /** * Interface that specifies the retry behavior */ From 836f1d1c663826e6042463f0a19c379153484e4b Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 3 Jun 2020 17:44:56 +0000 Subject: [PATCH 4/8] chore: codegen for adding retryable in Error --- clients/client-accessanalyzer/models/index.ts | 2 ++ clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts | 2 ++ clients/client-app-mesh/models/index.ts | 2 ++ clients/client-app-mesh/protocols/Aws_restJson1_1.ts | 2 ++ clients/client-codeguruprofiler/models/index.ts | 3 +++ clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts | 3 +++ 6 files changed, 14 insertions(+) diff --git a/clients/client-accessanalyzer/models/index.ts b/clients/client-accessanalyzer/models/index.ts index c36c2249fcc2..5102345c35bc 100644 --- a/clients/client-accessanalyzer/models/index.ts +++ b/clients/client-accessanalyzer/models/index.ts @@ -763,6 +763,7 @@ export interface InternalServerException $MetadataBearer { name: "InternalServerException"; $fault: "server"; + $retryable: {}; message: string | undefined; /** *

The seconds to wait to retry.

@@ -1213,6 +1214,7 @@ export interface ThrottlingException $MetadataBearer { name: "ThrottlingException"; $fault: "client"; + $retryable: {}; message: string | undefined; /** *

The seconds to wait to retry.

diff --git a/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts b/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts index bb1ab69b15a4..30eabda8f161 100644 --- a/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts +++ b/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts @@ -2724,6 +2724,7 @@ const deserializeAws_restJson1_1InternalServerExceptionResponse = async ( const contents: InternalServerException = { name: "InternalServerException", $fault: "server", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined, retryAfterSeconds: undefined @@ -2798,6 +2799,7 @@ const deserializeAws_restJson1_1ThrottlingExceptionResponse = async ( const contents: ThrottlingException = { name: "ThrottlingException", $fault: "client", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined, retryAfterSeconds: undefined diff --git a/clients/client-app-mesh/models/index.ts b/clients/client-app-mesh/models/index.ts index 3ea2380c434b..b7ada9198d09 100644 --- a/clients/client-app-mesh/models/index.ts +++ b/clients/client-app-mesh/models/index.ts @@ -1654,6 +1654,7 @@ export interface InternalServerErrorException $MetadataBearer { name: "InternalServerErrorException"; $fault: "server"; + $retryable: {}; message?: string; } @@ -2549,6 +2550,7 @@ export interface ServiceUnavailableException $MetadataBearer { name: "ServiceUnavailableException"; $fault: "server"; + $retryable: {}; message?: string; } diff --git a/clients/client-app-mesh/protocols/Aws_restJson1_1.ts b/clients/client-app-mesh/protocols/Aws_restJson1_1.ts index 7839425393e9..2ca7be117c7a 100644 --- a/clients/client-app-mesh/protocols/Aws_restJson1_1.ts +++ b/clients/client-app-mesh/protocols/Aws_restJson1_1.ts @@ -5046,6 +5046,7 @@ const deserializeAws_restJson1_1InternalServerErrorExceptionResponse = async ( const contents: InternalServerErrorException = { name: "InternalServerErrorException", $fault: "server", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; @@ -5114,6 +5115,7 @@ const deserializeAws_restJson1_1ServiceUnavailableExceptionResponse = async ( const contents: ServiceUnavailableException = { name: "ServiceUnavailableException", $fault: "server", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; diff --git a/clients/client-codeguruprofiler/models/index.ts b/clients/client-codeguruprofiler/models/index.ts index 0f725f89d356..e6a155023ad4 100644 --- a/clients/client-codeguruprofiler/models/index.ts +++ b/clients/client-codeguruprofiler/models/index.ts @@ -69,6 +69,7 @@ export interface InternalServerException $MetadataBearer { name: "InternalServerException"; $fault: "server"; + $retryable: {}; message: string | undefined; } @@ -118,6 +119,7 @@ export interface ServiceQuotaExceededException $MetadataBearer { name: "ServiceQuotaExceededException"; $fault: "client"; + $retryable: {}; message: string | undefined; } @@ -139,6 +141,7 @@ export interface ThrottlingException $MetadataBearer { name: "ThrottlingException"; $fault: "client"; + $retryable: {}; message: string | undefined; } diff --git a/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts b/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts index 0bf819ca17fc..5db1859606c3 100644 --- a/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts +++ b/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts @@ -1346,6 +1346,7 @@ const deserializeAws_restJson1_1InternalServerExceptionResponse = async ( const contents: InternalServerException = { name: "InternalServerException", $fault: "server", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; @@ -1380,6 +1381,7 @@ const deserializeAws_restJson1_1ServiceQuotaExceededExceptionResponse = async ( const contents: ServiceQuotaExceededException = { name: "ServiceQuotaExceededException", $fault: "client", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; @@ -1397,6 +1399,7 @@ const deserializeAws_restJson1_1ThrottlingExceptionResponse = async ( const contents: ThrottlingException = { name: "ThrottlingException", $fault: "client", + $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; From 6243fd4c6fbcc00571e96f9dafd2dad1519d05ce Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:19:06 +0000 Subject: [PATCH 5/8] feat: check for $retryable.throttling in isThrottlingError --- .../src/index.spec.ts | 28 ++++++++++++++++--- .../service-error-classification/src/index.ts | 3 +- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/service-error-classification/src/index.spec.ts b/packages/service-error-classification/src/index.spec.ts index 159d9ff5bace..cd488774b84a 100644 --- a/packages/service-error-classification/src/index.spec.ts +++ b/packages/service-error-classification/src/index.spec.ts @@ -5,17 +5,22 @@ import { TRANSIENT_ERROR_STATUS_CODES } from "./constants"; import { isClockSkewError, isThrottlingError, isTransientError } from "./index"; -import { SdkError } from "@aws-sdk/smithy-client"; +import { SdkError, RetryableTrait } from "@aws-sdk/smithy-client"; const checkForErrorType = ( isErrorTypeFunc: (error: SdkError) => boolean, - options: { name?: string; httpStatusCode?: number }, + options: { + name?: string; + httpStatusCode?: number; + $retryable?: RetryableTrait; + }, errorTypeResult: boolean ) => { - const { name, httpStatusCode } = options; + const { name, httpStatusCode, $retryable } = options; const error = Object.assign(new Error(), { name, - $metadata: { httpStatusCode } + $metadata: { httpStatusCode }, + $retryable }); expect(isErrorTypeFunc(error as SdkError)).toBe(errorTypeResult); }; @@ -54,6 +59,21 @@ describe("isThrottlingError", () => { break; } } + + it("should declare error with $retryable.throttling set to true to be a Throttling error", () => { + const $retryable = { throttling: true }; + checkForErrorType(isThrottlingError, { $retryable }, true); + }); + + it("should not declare error with $retryable.throttling set to false to be a Throttling error", () => { + const $retryable = { throttling: false }; + checkForErrorType(isThrottlingError, { $retryable }, false); + }); + + it("should not declare error with $retryable.throttling not set to be a Throttling error", () => { + const $retryable = {}; + checkForErrorType(isThrottlingError, { $retryable }, false); + }); }); describe("isTransientError", () => { diff --git a/packages/service-error-classification/src/index.ts b/packages/service-error-classification/src/index.ts index 4c6844a45a64..508199a92638 100644 --- a/packages/service-error-classification/src/index.ts +++ b/packages/service-error-classification/src/index.ts @@ -10,7 +10,8 @@ export const isClockSkewError = (error: SdkError) => CLOCK_SKEW_ERROR_CODES.includes(error.name); export const isThrottlingError = (error: SdkError) => - THROTTLING_ERROR_CODES.includes(error.name); + THROTTLING_ERROR_CODES.includes(error.name) || + error.$retryable?.throttling == true; export const isTransientError = (error: SdkError) => TRANSIENT_ERROR_CODES.includes(error.name) || From 46a74c2c50259c455ee2781f8fe618cd6edbca83 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:38:40 +0000 Subject: [PATCH 6/8] feat: add isRetryableByTrait in service-error-classification --- .../middleware-retry/src/retryDecider.spec.ts | 16 ++++++++++++++++ packages/middleware-retry/src/retryDecider.ts | 2 ++ .../src/index.spec.ts | 18 +++++++++++++++++- .../service-error-classification/src/index.ts | 3 +++ 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/middleware-retry/src/retryDecider.spec.ts b/packages/middleware-retry/src/retryDecider.spec.ts index 7c4e7d1d9d63..15ed0732cfee 100644 --- a/packages/middleware-retry/src/retryDecider.spec.ts +++ b/packages/middleware-retry/src/retryDecider.spec.ts @@ -1,4 +1,5 @@ import { + isRetryableByTrait, isClockSkewError, isThrottlingError, isTransientError @@ -7,6 +8,7 @@ import { defaultRetryDecider } from "./retryDecider"; import { SdkError } from "@aws-sdk/smithy-client"; jest.mock("@aws-sdk/service-error-classification", () => ({ + isRetryableByTrait: jest.fn().mockReturnValue(false), isClockSkewError: jest.fn().mockReturnValue(false), isThrottlingError: jest.fn().mockReturnValue(false), isTransientError: jest.fn().mockReturnValue(false) @@ -22,6 +24,16 @@ describe("defaultRetryDecider", () => { it("should return false when the provided error is falsy", () => { expect(defaultRetryDecider(null as any)).toBe(false); + expect((isRetryableByTrait as jest.Mock).mock.calls.length).toBe(0); + expect((isClockSkewError as jest.Mock).mock.calls.length).toBe(0); + expect((isThrottlingError as jest.Mock).mock.calls.length).toBe(0); + expect((isTransientError as jest.Mock).mock.calls.length).toBe(0); + }); + + it("should return true for RetryableByTrait error", () => { + (isRetryableByTrait as jest.Mock).mockReturnValueOnce(true); + expect(defaultRetryDecider(createMockError())).toBe(true); + expect((isRetryableByTrait as jest.Mock).mock.calls.length).toBe(1); expect((isClockSkewError as jest.Mock).mock.calls.length).toBe(0); expect((isThrottlingError as jest.Mock).mock.calls.length).toBe(0); expect((isTransientError as jest.Mock).mock.calls.length).toBe(0); @@ -30,6 +42,7 @@ describe("defaultRetryDecider", () => { it("should return true for ClockSkewError", () => { (isClockSkewError as jest.Mock).mockReturnValueOnce(true); expect(defaultRetryDecider(createMockError())).toBe(true); + expect((isRetryableByTrait as jest.Mock).mock.calls.length).toBe(1); expect((isClockSkewError as jest.Mock).mock.calls.length).toBe(1); expect((isThrottlingError as jest.Mock).mock.calls.length).toBe(0); expect((isTransientError as jest.Mock).mock.calls.length).toBe(0); @@ -38,6 +51,7 @@ describe("defaultRetryDecider", () => { it("should return true for ThrottlingError", () => { (isThrottlingError as jest.Mock).mockReturnValueOnce(true); expect(defaultRetryDecider(createMockError())).toBe(true); + expect((isRetryableByTrait as jest.Mock).mock.calls.length).toBe(1); expect((isClockSkewError as jest.Mock).mock.calls.length).toBe(1); expect((isThrottlingError as jest.Mock).mock.calls.length).toBe(1); expect((isTransientError as jest.Mock).mock.calls.length).toBe(0); @@ -46,6 +60,7 @@ describe("defaultRetryDecider", () => { it("should return true for TransientError", () => { (isTransientError as jest.Mock).mockReturnValueOnce(true); expect(defaultRetryDecider(createMockError())).toBe(true); + expect((isRetryableByTrait as jest.Mock).mock.calls.length).toBe(1); expect((isClockSkewError as jest.Mock).mock.calls.length).toBe(1); expect((isThrottlingError as jest.Mock).mock.calls.length).toBe(1); expect((isTransientError as jest.Mock).mock.calls.length).toBe(1); @@ -53,6 +68,7 @@ describe("defaultRetryDecider", () => { it("should return false for other errors", () => { expect(defaultRetryDecider(createMockError())).toBe(false); + expect((isRetryableByTrait as jest.Mock).mock.calls.length).toBe(1); expect((isClockSkewError as jest.Mock).mock.calls.length).toBe(1); expect((isThrottlingError as jest.Mock).mock.calls.length).toBe(1); expect((isTransientError as jest.Mock).mock.calls.length).toBe(1); diff --git a/packages/middleware-retry/src/retryDecider.ts b/packages/middleware-retry/src/retryDecider.ts index 192c92ce8ed0..83a3fec2bd7c 100644 --- a/packages/middleware-retry/src/retryDecider.ts +++ b/packages/middleware-retry/src/retryDecider.ts @@ -1,5 +1,6 @@ import { isClockSkewError, + isRetryableByTrait, isThrottlingError, isTransientError } from "@aws-sdk/service-error-classification"; @@ -11,6 +12,7 @@ export const defaultRetryDecider = (error: SdkError) => { } return ( + isRetryableByTrait(error) || isClockSkewError(error) || isThrottlingError(error) || isTransientError(error) diff --git a/packages/service-error-classification/src/index.spec.ts b/packages/service-error-classification/src/index.spec.ts index cd488774b84a..2ab1da02f3b6 100644 --- a/packages/service-error-classification/src/index.spec.ts +++ b/packages/service-error-classification/src/index.spec.ts @@ -4,7 +4,12 @@ import { TRANSIENT_ERROR_CODES, TRANSIENT_ERROR_STATUS_CODES } from "./constants"; -import { isClockSkewError, isThrottlingError, isTransientError } from "./index"; +import { + isRetryableByTrait, + isClockSkewError, + isThrottlingError, + isTransientError +} from "./index"; import { SdkError, RetryableTrait } from "@aws-sdk/smithy-client"; const checkForErrorType = ( @@ -25,6 +30,17 @@ const checkForErrorType = ( expect(isErrorTypeFunc(error as SdkError)).toBe(errorTypeResult); }; +describe("isRetryableByTrait", () => { + it("should declare error with $retryable set to be a Retryable by trait", () => { + const $retryable = {}; + checkForErrorType(isRetryableByTrait, { $retryable }, true); + }); + + it("should not declare error with $retryable not set to be a Retryable by trait", () => { + checkForErrorType(isRetryableByTrait, {}, false); + }); +}); + describe("isClockSkewError", () => { CLOCK_SKEW_ERROR_CODES.forEach(name => { it(`should declare error with the name "${name}" to be a ClockSkew error`, () => { diff --git a/packages/service-error-classification/src/index.ts b/packages/service-error-classification/src/index.ts index 508199a92638..f046b22d118d 100644 --- a/packages/service-error-classification/src/index.ts +++ b/packages/service-error-classification/src/index.ts @@ -6,6 +6,9 @@ import { } from "./constants"; import { SdkError } from "@aws-sdk/smithy-client"; +export const isRetryableByTrait = (error: SdkError) => + error.$retryable !== undefined; + export const isClockSkewError = (error: SdkError) => CLOCK_SKEW_ERROR_CODES.includes(error.name); From 3ef26cf52dbdcad90770beffe56e221029ed35fb Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 3 Jun 2020 18:40:28 +0000 Subject: [PATCH 7/8] Revert "chore: codegen for adding retryable in Error" This reverts commit 836f1d1c663826e6042463f0a19c379153484e4b. --- clients/client-accessanalyzer/models/index.ts | 2 -- clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts | 2 -- clients/client-app-mesh/models/index.ts | 2 -- clients/client-app-mesh/protocols/Aws_restJson1_1.ts | 2 -- clients/client-codeguruprofiler/models/index.ts | 3 --- clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts | 3 --- 6 files changed, 14 deletions(-) diff --git a/clients/client-accessanalyzer/models/index.ts b/clients/client-accessanalyzer/models/index.ts index 5102345c35bc..c36c2249fcc2 100644 --- a/clients/client-accessanalyzer/models/index.ts +++ b/clients/client-accessanalyzer/models/index.ts @@ -763,7 +763,6 @@ export interface InternalServerException $MetadataBearer { name: "InternalServerException"; $fault: "server"; - $retryable: {}; message: string | undefined; /** *

The seconds to wait to retry.

@@ -1214,7 +1213,6 @@ export interface ThrottlingException $MetadataBearer { name: "ThrottlingException"; $fault: "client"; - $retryable: {}; message: string | undefined; /** *

The seconds to wait to retry.

diff --git a/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts b/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts index 30eabda8f161..bb1ab69b15a4 100644 --- a/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts +++ b/clients/client-accessanalyzer/protocols/Aws_restJson1_1.ts @@ -2724,7 +2724,6 @@ const deserializeAws_restJson1_1InternalServerExceptionResponse = async ( const contents: InternalServerException = { name: "InternalServerException", $fault: "server", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined, retryAfterSeconds: undefined @@ -2799,7 +2798,6 @@ const deserializeAws_restJson1_1ThrottlingExceptionResponse = async ( const contents: ThrottlingException = { name: "ThrottlingException", $fault: "client", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined, retryAfterSeconds: undefined diff --git a/clients/client-app-mesh/models/index.ts b/clients/client-app-mesh/models/index.ts index b7ada9198d09..3ea2380c434b 100644 --- a/clients/client-app-mesh/models/index.ts +++ b/clients/client-app-mesh/models/index.ts @@ -1654,7 +1654,6 @@ export interface InternalServerErrorException $MetadataBearer { name: "InternalServerErrorException"; $fault: "server"; - $retryable: {}; message?: string; } @@ -2550,7 +2549,6 @@ export interface ServiceUnavailableException $MetadataBearer { name: "ServiceUnavailableException"; $fault: "server"; - $retryable: {}; message?: string; } diff --git a/clients/client-app-mesh/protocols/Aws_restJson1_1.ts b/clients/client-app-mesh/protocols/Aws_restJson1_1.ts index 2ca7be117c7a..7839425393e9 100644 --- a/clients/client-app-mesh/protocols/Aws_restJson1_1.ts +++ b/clients/client-app-mesh/protocols/Aws_restJson1_1.ts @@ -5046,7 +5046,6 @@ const deserializeAws_restJson1_1InternalServerErrorExceptionResponse = async ( const contents: InternalServerErrorException = { name: "InternalServerErrorException", $fault: "server", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; @@ -5115,7 +5114,6 @@ const deserializeAws_restJson1_1ServiceUnavailableExceptionResponse = async ( const contents: ServiceUnavailableException = { name: "ServiceUnavailableException", $fault: "server", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; diff --git a/clients/client-codeguruprofiler/models/index.ts b/clients/client-codeguruprofiler/models/index.ts index e6a155023ad4..0f725f89d356 100644 --- a/clients/client-codeguruprofiler/models/index.ts +++ b/clients/client-codeguruprofiler/models/index.ts @@ -69,7 +69,6 @@ export interface InternalServerException $MetadataBearer { name: "InternalServerException"; $fault: "server"; - $retryable: {}; message: string | undefined; } @@ -119,7 +118,6 @@ export interface ServiceQuotaExceededException $MetadataBearer { name: "ServiceQuotaExceededException"; $fault: "client"; - $retryable: {}; message: string | undefined; } @@ -141,7 +139,6 @@ export interface ThrottlingException $MetadataBearer { name: "ThrottlingException"; $fault: "client"; - $retryable: {}; message: string | undefined; } diff --git a/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts b/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts index 5db1859606c3..0bf819ca17fc 100644 --- a/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts +++ b/clients/client-codeguruprofiler/protocols/Aws_restJson1_1.ts @@ -1346,7 +1346,6 @@ const deserializeAws_restJson1_1InternalServerExceptionResponse = async ( const contents: InternalServerException = { name: "InternalServerException", $fault: "server", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; @@ -1381,7 +1380,6 @@ const deserializeAws_restJson1_1ServiceQuotaExceededExceptionResponse = async ( const contents: ServiceQuotaExceededException = { name: "ServiceQuotaExceededException", $fault: "client", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; @@ -1399,7 +1397,6 @@ const deserializeAws_restJson1_1ThrottlingExceptionResponse = async ( const contents: ThrottlingException = { name: "ThrottlingException", $fault: "client", - $retryable: {}, $metadata: deserializeMetadata(parsedOutput), message: undefined }; From 8780d26da9914f2e734d905012d5a979bf85b332 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 3 Jun 2020 21:41:25 +0000 Subject: [PATCH 8/8] chore: move @aws-sdk/smithy-client to devDependencies --- packages/middleware-retry/package.json | 2 +- packages/service-error-classification/package.json | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/middleware-retry/package.json b/packages/middleware-retry/package.json index a4bd3a6e5fd0..663972a363ec 100644 --- a/packages/middleware-retry/package.json +++ b/packages/middleware-retry/package.json @@ -15,12 +15,12 @@ "license": "Apache-2.0", "dependencies": { "@aws-sdk/service-error-classification": "1.0.0-gamma.1", - "@aws-sdk/smithy-client": "1.0.0-gamma.1", "@aws-sdk/types": "1.0.0-gamma.1", "tslib": "^1.8.0" }, "devDependencies": { "@aws-sdk/protocol-http": "1.0.0-gamma.1", + "@aws-sdk/smithy-client": "1.0.0-gamma.1", "@types/jest": "^25.1.4", "jest": "^25.1.0", "typescript": "~3.8.3" diff --git a/packages/service-error-classification/package.json b/packages/service-error-classification/package.json index a6f9e649a530..56623b99acc2 100644 --- a/packages/service-error-classification/package.json +++ b/packages/service-error-classification/package.json @@ -13,10 +13,8 @@ "url": "https://aws.amazon.com/javascript/" }, "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/smithy-client": "1.0.0-gamma.1" - }, "devDependencies": { + "@aws-sdk/smithy-client": "1.0.0-gamma.1", "@types/jest": "^25.1.4", "jest": "^25.1.0", "typescript": "~3.8.3"