Skip to content

Commit a86e44f

Browse files
committed
feat: move some config components to middleware folder
* signing middleware * retry middleware; Also update retry config interface by introducing RetryStrategy class
1 parent a3808f0 commit a86e44f

File tree

17 files changed

+259
-226
lines changed

17 files changed

+259
-226
lines changed

clients/node/client-rds-data-node/RDSDataClient.ts

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { contentLengthPlugin } from "@aws-sdk/middleware-content-length";
22
import * as __aws_sdk_middleware_header_default from "@aws-sdk/middleware-header-default";
3-
import * as __aws_sdk_retry_middleware from "@aws-sdk/retry-middleware";
4-
import { signingPlugin } from "@aws-sdk/signing-middleware";
3+
import { retryPlugin, RetryConfig } from "@aws-sdk/retry-middleware";
4+
import { signingPlugin, AwsAuthConfiguration } from "@aws-sdk/signing-middleware";
55
import * as __aws_sdk_util_user_agent_node from "@aws-sdk/util-user-agent-node";
66
import {
77
RDSDataConfiguration,
88
RDSDataResolvedConfiguration,
99
RDSRuntimeConfiguration
1010
} from "./RDSDataConfiguration";
11-
import { AwsAuthConfiguration, RegionConfiguration, RetryConfig, EndpointsConfig, ProtocolConfig } from '@aws-sdk/config-resolver';
11+
import { RegionConfiguration, EndpointsConfig, ProtocolConfig } from '@aws-sdk/config-resolver';
1212
import { HttpOptions, MetadataBearer } from '@aws-sdk/types';
1313
import { SmithyClient } from "@aws-sdk/smithy-client";
1414

@@ -31,20 +31,9 @@ export class RDSDataClient extends SmithyClient<HttpOptions, InputTypesUnion, Ou
3131
this.config = intermediaConfig_4;
3232
super.use(contentLengthPlugin(this.config));
3333
if (this.config.maxRetries > 0) {
34-
this.middlewareStack.add(
35-
__aws_sdk_retry_middleware.retryMiddleware(
36-
this.config.maxRetries,
37-
this.config.retryDecider,
38-
this.config.delayDecider
39-
),
40-
{
41-
step: "finalizeRequest",
42-
priority: Infinity,
43-
tags: { RETRY: true }
44-
}
45-
);
34+
super.use(retryPlugin(this.config))
4635
}
47-
super.use(signingPlugin(this.config.signer));
36+
super.use(signingPlugin(this.config));
4837
this.middlewareStack.add(
4938
__aws_sdk_middleware_header_default.headerDefault({
5039
"User-Agent": this.config.defaultUserAgent

clients/node/client-rds-data-node/RDSDataConfiguration.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ import { RestJsonProtocol } from "@aws-sdk/protocol-rest-json";
99
import { fromUtf8, toUtf8 } from '@aws-sdk/util-utf8-node';
1010
import { fromBase64, toBase64 } from '@aws-sdk/util-base64-node';
1111
import { defaultUserAgent } from '@aws-sdk/util-user-agent-node';
12+
import { AwsAuthConfiguration, AwsAuthConfigurationInput } from '@aws-sdk/signing-middleware';
13+
import { RetryConfig, RetryConfigInput } from '@aws-sdk/retry-middleware';
1214
import { name, version } from './package.json';
13-
import { AwsAuthConfiguration, RegionConfiguration, RetryConfig, EndpointsConfig, ProtocolConfig, AWSClientRuntimeConfiguration } from '@aws-sdk/config-resolver';
15+
import { RegionConfiguration, EndpointsConfig, ProtocolConfig, AWSClientRuntimeConfiguration } from '@aws-sdk/config-resolver';
1416

1517
export type AWSClientRuntimeResolvedConfiguration = Required<AWSClientRuntimeConfiguration>;
1618

@@ -33,9 +35,9 @@ export const RDSRuntimeConfiguration: AWSClientRuntimeResolvedConfiguration = {
3335
}
3436

3537
export type RDSDataConfiguration = AWSClientRuntimeConfiguration &
36-
AwsAuthConfiguration.Input &
38+
AwsAuthConfigurationInput &
3739
RegionConfiguration.Input &
38-
RetryConfig.Input &
40+
RetryConfigInput &
3941
EndpointsConfig.Input &
4042
ProtocolConfig.Input
4143

packages/config-resolver/src/components.ts

Lines changed: 0 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
import {
22
Credentials,
33
Provider,
4-
RequestSigner,
54
HashConstructor,
6-
RetryDecider,
7-
DelayDecider,
85
UrlParser,
96
Protocol,
107
HttpOptions,
118
StreamCollector,
129
Decoder,
1310
Encoder
1411
} from "@aws-sdk/types";
15-
import { SignatureV4 } from "@aws-sdk/signature-v4";
1612
import {
1713
HttpEndpoint,
1814
HttpHandler,
@@ -123,56 +119,6 @@ export function normalizeEndpoint(
123119
return endpoint!;
124120
}
125121

126-
export namespace AwsAuthConfiguration {
127-
export interface Input {
128-
/**
129-
* The credentials used to sign requests.
130-
*/
131-
credentials?: Credentials | Provider<Credentials>;
132-
133-
/**
134-
* The signer to use when signing requests.
135-
*/
136-
signer?: RequestSigner;
137-
138-
/**
139-
* Whether to escape request path when signing the request
140-
*/
141-
signingEscapePath?: boolean;
142-
}
143-
interface PreviouslyResolved {
144-
credentialDefaultProvider: (input: any) => Provider<Credentials>;
145-
region: string | Provider<string>;
146-
signingName: string;
147-
sha256: HashConstructor;
148-
}
149-
export type Resolved = {
150-
credentials: Provider<Credentials>;
151-
signer: RequestSigner;
152-
signingEscapePath: boolean;
153-
};
154-
export function resolve<T>(
155-
input: T & Input & PreviouslyResolved
156-
): T & Resolved {
157-
let credentials =
158-
input.credentials || input.credentialDefaultProvider(input as any);
159-
const normalizedCreds = normalizeProvider(credentials);
160-
const signingEscapePath = input.signingEscapePath || false;
161-
return {
162-
...input,
163-
signingEscapePath,
164-
credentials: normalizedCreds,
165-
signer: new SignatureV4({
166-
credentials: normalizedCreds,
167-
region: input.region,
168-
service: input.signingName,
169-
sha256: input.sha256,
170-
uriEscapePath: signingEscapePath
171-
})
172-
};
173-
}
174-
}
175-
176122
export namespace RegionConfiguration {
177123
export interface Input {
178124
/**
@@ -197,25 +143,6 @@ export namespace RegionConfiguration {
197143
}
198144
}
199145

200-
export namespace RetryConfig {
201-
export interface Input {
202-
maxRetries?: number;
203-
retryDecider?: RetryDecider;
204-
delayDecider?: DelayDecider;
205-
}
206-
export interface Resolved {
207-
maxRetries: number;
208-
retryDecider?: RetryDecider;
209-
delayDecider?: DelayDecider;
210-
}
211-
export function resolve<T>(input: T & Input): T & Resolved {
212-
return {
213-
...input,
214-
maxRetries: input.maxRetries === undefined ? 3 : input.maxRetries
215-
};
216-
}
217-
}
218-
219146
export namespace EndpointsConfig {
220147
export interface Input {
221148
/**

packages/retry-middleware/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
},
2121
"devDependencies": {
2222
"@types/jest": "^24.0.12",
23+
"@aws-sdk/protocol-http": "^0.1.0-preview.1",
2324
"jest": "^24.7.1",
2425
"typescript": "~3.4.0"
2526
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { RetryStrategy } from "@aws-sdk/types";
2+
import { ExponentialBackOffStrategy } from "./defaultStrategy";
3+
4+
export namespace RetryConfig {
5+
export interface Input {
6+
maxRetries?: number;
7+
retryStrategy?: RetryStrategy;
8+
}
9+
export interface Resolved {
10+
maxRetries: number;
11+
retryStrategy: RetryStrategy;
12+
}
13+
export function resolve<T>(input: T & Input): T & Resolved {
14+
const maxRetries = input.maxRetries === undefined ? 3 : input.maxRetries;
15+
return {
16+
...input,
17+
maxRetries,
18+
retryStrategy:
19+
input.retryStrategy || new ExponentialBackOffStrategy(maxRetries)
20+
};
21+
}
22+
}
23+
24+
//export separately for showing comment block in Intellisense
25+
export type RetryConfigInput = RetryConfig.Input;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import {
2+
DEFAULT_RETRY_DELAY_BASE,
3+
THROTTLING_RETRY_DELAY_BASE
4+
} from "./constants";
5+
import { defaultDelayDecider } from "./delayDecider";
6+
import { defaultRetryDecider } from "./retryDecider";
7+
import { isThrottlingError } from "@aws-sdk/service-error-classification";
8+
import { RetryStrategy, SdkError } from "@aws-sdk/types";
9+
10+
export class ExponentialBackOffStrategy implements RetryStrategy {
11+
constructor(public readonly maxRetries: number) {}
12+
shouldRetry(error: SdkError, retryAttempted: number) {
13+
return retryAttempted < this.maxRetries && defaultRetryDecider(error);
14+
}
15+
computeDelayBeforeNextRetry(error: SdkError, retryAttempted: number): number {
16+
return defaultDelayDecider(
17+
isThrottlingError(error)
18+
? THROTTLING_RETRY_DELAY_BASE
19+
: DEFAULT_RETRY_DELAY_BASE,
20+
retryAttempted
21+
);
22+
}
23+
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export * from "./delayDecider";
2-
export * from "./retryDecider";
31
export * from "./retryMiddleware";
2+
export * from "./defaultStrategy";
3+
export * from "./configurations";
Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,37 @@
11
import { defaultRetryDecider } from "./retryDecider";
22

33
describe("defaultRetryDecider", () => {
4-
const decider = defaultRetryDecider();
5-
64
it("should return false when the provided error is falsy", () => {
7-
expect(decider(null as any)).toBe(false);
5+
expect(defaultRetryDecider(null as any)).toBe(false);
86
});
97

108
it("should return true if the error was tagged as a connection error", () => {
119
const err: Error & { connectionError?: boolean } = new Error();
1210
err.connectionError = true;
13-
expect(decider(err)).toBe(true);
11+
expect(defaultRetryDecider(err)).toBe(true);
1412
});
1513

1614
for (const httpStatusCode of [429, 500, 502, 503, 504, 509]) {
1715
it(`should return true if the error represents a service response with an HTTP status code of ${httpStatusCode}`, () => {
1816
const err: any = new Error();
1917
err.$metadata = { httpStatusCode };
20-
expect(decider(err)).toBe(true);
18+
expect(defaultRetryDecider(err)).toBe(true);
2119
});
2220
}
2321

2422
it('should return true if the response represents a "still processing" error', () => {
2523
const err = new Error();
2624
err.name = "PriorRequestNotComplete";
27-
expect(decider(err)).toBe(true);
25+
expect(defaultRetryDecider(err)).toBe(true);
2826
});
2927

3028
it("should return true if the response represents a throttling error", () => {
3129
const err = new Error();
3230
err.name = "TooManyRequestsException";
33-
expect(decider(err)).toBe(true);
31+
expect(defaultRetryDecider(err)).toBe(true);
3432
});
3533

3634
it("should return false for other errors", () => {
37-
expect(decider(new Error())).toBe(false);
38-
});
39-
40-
describe("clock skew retries enabled", () => {
41-
const decider = defaultRetryDecider(true);
42-
43-
it("should return true if the response represents a clock skew error", () => {
44-
const err = new Error();
45-
err.name = "RequestTimeTooSkewed";
46-
expect(decider(err)).toBe(true);
47-
});
35+
expect(defaultRetryDecider(new Error())).toBe(false);
4836
});
4937
});

packages/retry-middleware/src/retryDecider.ts

Lines changed: 21 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,35 +4,31 @@ import {
44
isStillProcessingError,
55
isThrottlingError
66
} from "@aws-sdk/service-error-classification";
7-
import { MetadataBearer, SdkError, RetryDecider } from "@aws-sdk/types";
7+
import { MetadataBearer, SdkError } from "@aws-sdk/types";
88

9-
export function defaultRetryDecider(
10-
retryClockSkewErrors = false
11-
): RetryDecider {
12-
return (error: SdkError) => {
13-
if (!error) {
14-
return false;
15-
}
9+
export const defaultRetryDecider = (error: SdkError) => {
10+
if (!error) {
11+
return false;
12+
}
1613

17-
if (error.connectionError) {
18-
return true;
19-
}
14+
if (error.connectionError) {
15+
return true;
16+
}
2017

21-
if (
22-
hasMetadata(error) &&
23-
error.$metadata.httpStatusCode &&
24-
RETRYABLE_STATUS_CODES.has(error.$metadata.httpStatusCode)
25-
) {
26-
return true;
27-
}
18+
if (
19+
hasMetadata(error) &&
20+
error.$metadata.httpStatusCode &&
21+
RETRYABLE_STATUS_CODES.has(error.$metadata.httpStatusCode)
22+
) {
23+
return true;
24+
}
2825

29-
return (
30-
isStillProcessingError(error) ||
31-
isThrottlingError(error) ||
32-
(retryClockSkewErrors && isClockSkewError(error))
33-
);
34-
};
35-
}
26+
return (
27+
isStillProcessingError(error) ||
28+
isThrottlingError(error) ||
29+
isClockSkewError(error)
30+
);
31+
};
3632

3733
function hasMetadata(error: any): error is MetadataBearer {
3834
return error && error.$metadata;

0 commit comments

Comments
 (0)