From fae1f70d305e61d2ed59448ab4bf40a84da88571 Mon Sep 17 00:00:00 2001 From: skiyani <52760558+skiyani@users.noreply.github.com> Date: Tue, 15 Dec 2020 12:11:21 -0600 Subject: [PATCH] feat(appmesh): add timeout support to Routes (#11973) Add support to http/http2/grpc/tpc route timeouts. Reference links for [HttpTimeout](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-route-httptimeout.html), [GrpcTimeout](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-route-grpctimeout.html), and [TcpTimeout](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-appmesh-route-tcptimeout.html). (Http2 uses the HttpTimeout object). closes https://github.com/aws/aws-cdk/issues/11643 ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-appmesh/README.md | 5 ++ .../@aws-cdk/aws-appmesh/lib/route-spec.ts | 62 +++++++++++++++++- .../aws-appmesh/lib/shared-interfaces.ts | 50 ++++++++++++++ .../aws-appmesh/lib/virtual-node-listener.ts | 52 +-------------- packages/@aws-cdk/aws-appmesh/package.json | 5 +- .../aws-appmesh/test/integ.mesh.expected.json | 26 ++++++++ .../@aws-cdk/aws-appmesh/test/integ.mesh.ts | 11 ++++ .../@aws-cdk/aws-appmesh/test/test.route.ts | 65 +++++++++++++++++++ 8 files changed, 223 insertions(+), 53 deletions(-) diff --git a/packages/@aws-cdk/aws-appmesh/README.md b/packages/@aws-cdk/aws-appmesh/README.md index 0b736380de817..9a4fcddf386cc 100644 --- a/packages/@aws-cdk/aws-appmesh/README.md +++ b/packages/@aws-cdk/aws-appmesh/README.md @@ -289,6 +289,7 @@ The `tcp()`, `http()` and `http2()` methods provide the spec necessary to define For HTTP based routes, the match field can be used to match on a route prefix. By default, an HTTP based route will match on `/`. All matches must start with a leading `/`. +The timeout field can also be specified for `idle` and `perRequest` timeouts. ```ts router.addRoute('route-http', { @@ -301,6 +302,10 @@ router.addRoute('route-http', { match: { serviceName: 'my-service.default.svc.cluster.local', }, + timeout: { + idle : Duration.seconds(2), + perRequest: Duration.seconds(1), + }, }), }); ``` diff --git a/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts b/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts index b015bd4580171..b3ce09f0c0031 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/route-spec.ts @@ -1,6 +1,6 @@ import * as cdk from '@aws-cdk/core'; import { CfnRoute } from './appmesh.generated'; -import { Protocol } from './shared-interfaces'; +import { Protocol, HttpTimeout, GrpcTimeout, TcpTimeout } from './shared-interfaces'; import { IVirtualNode } from './virtual-node'; /** @@ -58,6 +58,13 @@ export interface HttpRouteSpecOptions { * List of targets that traffic is routed to when a request matches the route */ readonly weightedTargets: WeightedTarget[]; + + /** + * An object that represents a http timeout + * + * @default - None + */ + readonly timeout?: HttpTimeout; } /** @@ -68,6 +75,13 @@ export interface TcpRouteSpecOptions { * List of targets that traffic is routed to when a request matches the route */ readonly weightedTargets: WeightedTarget[]; + + /** + * An object that represents a tcp timeout + * + * @default - None + */ + readonly timeout?: TcpTimeout; } /** @@ -79,6 +93,13 @@ export interface GrpcRouteSpecOptions { */ readonly match: GrpcRouteMatch; + /** + * An object that represents a grpc timeout + * + * @default - None + */ + readonly timeout?: GrpcTimeout; + /** * List of targets that traffic is routed to when a request matches the route */ @@ -169,6 +190,11 @@ class HttpRouteSpec extends RouteSpec { */ public readonly match?: HttpRouteMatch; + /** + * The criteria for determining a timeout configuration + */ + public readonly timeout?: HttpTimeout; + /** * List of targets that traffic is routed to when a request matches the route */ @@ -179,6 +205,7 @@ class HttpRouteSpec extends RouteSpec { this.protocol = protocol; this.match = props.match; this.weightedTargets = props.weightedTargets; + this.timeout = props.timeout; } public bind(_scope: cdk.Construct): RouteSpecConfig { @@ -193,6 +220,7 @@ class HttpRouteSpec extends RouteSpec { match: { prefix: prefixPath, }, + timeout: renderTimeout(this.timeout), }; return { httpRouteSpec: this.protocol === Protocol.HTTP ? httpConfig : undefined, @@ -207,9 +235,15 @@ class TcpRouteSpec extends RouteSpec { */ public readonly weightedTargets: WeightedTarget[]; + /** + * The criteria for determining a timeout configuration + */ + public readonly timeout?: TcpTimeout; + constructor(props: TcpRouteSpecOptions) { super(); this.weightedTargets = props.weightedTargets; + this.timeout = props.timeout; } public bind(_scope: cdk.Construct): RouteSpecConfig { @@ -218,6 +252,7 @@ class TcpRouteSpec extends RouteSpec { action: { weightedTargets: renderWeightedTargets(this.weightedTargets), }, + timeout: renderTimeout(this.timeout), }, }; } @@ -226,11 +261,13 @@ class TcpRouteSpec extends RouteSpec { class GrpcRouteSpec extends RouteSpec { public readonly weightedTargets: WeightedTarget[]; public readonly match: GrpcRouteMatch; + public readonly timeout?: GrpcTimeout; constructor(props: GrpcRouteSpecOptions) { super(); this.weightedTargets = props.weightedTargets; this.match = props.match; + this.timeout = props.timeout; } public bind(_scope: cdk.Construct): RouteSpecConfig { @@ -242,6 +279,7 @@ class GrpcRouteSpec extends RouteSpec { match: { serviceName: this.match.serviceName, }, + timeout: renderTimeout(this.timeout), }, }; } @@ -260,3 +298,25 @@ function renderWeightedTargets(weightedTargets: WeightedTarget[]): CfnRoute.Weig } return renderedTargets; } + +/** + * Utility method to construct a route timeout object + */ +function renderTimeout(timeout?: HttpTimeout): CfnRoute.HttpTimeoutProperty | undefined { + return timeout + ? { + idle: timeout?.idle !== undefined + ? { + unit: 'ms', + value: timeout?.idle.toMilliseconds(), + } + : undefined, + perRequest: timeout?.perRequest !== undefined + ? { + unit: 'ms', + value: timeout?.perRequest.toMilliseconds(), + } + : undefined, + } + : undefined; +} diff --git a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts index c8b3ba88f6378..cbd574489f9c4 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/shared-interfaces.ts @@ -1,6 +1,56 @@ import * as cdk from '@aws-cdk/core'; import { CfnVirtualGateway, CfnVirtualNode } from './appmesh.generated'; +/** + * Represents timeouts for HTTP protocols. + */ +export interface HttpTimeout { + /** + * Represents an idle timeout. The amount of time that a connection may be idle. + * + * @default - none + */ + readonly idle?: cdk.Duration; + + /** + * Represents per request timeout. + * + * @default - 15 s + */ + readonly perRequest?: cdk.Duration; +} + +/** + * Represents timeouts for GRPC protocols. + */ +export interface GrpcTimeout { + /** + * Represents an idle timeout. The amount of time that a connection may be idle. + * + * @default - none + */ + readonly idle?: cdk.Duration; + + /** + * Represents per request timeout. + * + * @default - 15 s + */ + readonly perRequest?: cdk.Duration; +} + +/** + * Represents timeouts for TCP protocols. + */ +export interface TcpTimeout { + /** + * Represents an idle timeout. The amount of time that a connection may be idle. + * + * @default - none + */ + readonly idle?: cdk.Duration; +} + /** * Enum of supported AppMesh protocols */ diff --git a/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts b/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts index e3e433d8e25d8..5793a746ee968 100644 --- a/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts +++ b/packages/@aws-cdk/aws-appmesh/lib/virtual-node-listener.ts @@ -1,7 +1,7 @@ import * as cdk from '@aws-cdk/core'; import { CfnVirtualNode } from './appmesh.generated'; import { validateHealthChecks } from './private/utils'; -import { HealthCheck, Protocol } from './shared-interfaces'; +import { HealthCheck, Protocol, HttpTimeout, GrpcTimeout, TcpTimeout } from './shared-interfaces'; /** * Properties for a VirtualNode listener @@ -68,56 +68,6 @@ export interface TcpVirtualNodeListenerOptions extends VirtualNodeListenerCommon readonly timeout?: TcpTimeout; } -/** - * Represents timeouts for HTTP protocols. - */ -export interface HttpTimeout { - /** - * Represents an idle timeout. The amount of time that a connection may be idle. - * - * @default - none - */ - readonly idle?: cdk.Duration; - - /** - * Represents per request timeout. - * - * @default - 15 s - */ - readonly perRequest?: cdk.Duration; -} - -/** - * Represents timeouts for GRPC protocols. - */ -export interface GrpcTimeout { - /** - * Represents an idle timeout. The amount of time that a connection may be idle. - * - * @default - none - */ - readonly idle?: cdk.Duration; - - /** - * Represents per request timeout. - * - * @default - 15 s - */ - readonly perRequest?: cdk.Duration; -} - -/** - * Represents timeouts for TCP protocols. - */ -export interface TcpTimeout { - /** - * Represents an idle timeout. The amount of time that a connection may be idle. - * - * @default - none - */ - readonly idle?: cdk.Duration; -} - /** * Defines listener for a VirtualNode */ diff --git a/packages/@aws-cdk/aws-appmesh/package.json b/packages/@aws-cdk/aws-appmesh/package.json index c956c2e77c844..fad86447a4fe3 100644 --- a/packages/@aws-cdk/aws-appmesh/package.json +++ b/packages/@aws-cdk/aws-appmesh/package.json @@ -180,7 +180,10 @@ "duration-prop-type:@aws-cdk/aws-appmesh.GrpcVirtualNodeListenerOptions.timeout", "duration-prop-type:@aws-cdk/aws-appmesh.HttpVirtualNodeListenerOptions.timeout", "duration-prop-type:@aws-cdk/aws-appmesh.Http2VirtualNodeListenerOptions.timeout", - "duration-prop-type:@aws-cdk/aws-appmesh.TcpVirtualNodeListenerOptions.timeout" + "duration-prop-type:@aws-cdk/aws-appmesh.TcpVirtualNodeListenerOptions.timeout", + "duration-prop-type:@aws-cdk/aws-appmesh.GrpcRouteSpecOptions.timeout", + "duration-prop-type:@aws-cdk/aws-appmesh.HttpRouteSpecOptions.timeout", + "duration-prop-type:@aws-cdk/aws-appmesh.TcpRouteSpecOptions.timeout" ] }, "stability": "experimental", diff --git a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json index e3a9f98c5a016..e642633387206 100644 --- a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json +++ b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.expected.json @@ -515,6 +515,16 @@ }, "Match": { "Prefix": "/" + }, + "Timeout": { + "Idle": { + "Unit": "ms", + "Value": 10000 + }, + "PerRequest": { + "Unit": "ms", + "Value": 10000 + } } } }, @@ -553,6 +563,16 @@ }, "Match": { "Prefix": "/path2" + }, + "Timeout": { + "Idle": { + "Unit": "ms", + "Value": 11000 + }, + "PerRequest": { + "Unit": "ms", + "Value": 11000 + } } } }, @@ -588,6 +608,12 @@ "Weight": 20 } ] + }, + "Timeout": { + "Idle": { + "Unit": "ms", + "Value": 12000 + } } } }, diff --git a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts index 6790f4c749316..2f1884b3f7e63 100644 --- a/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts +++ b/packages/@aws-cdk/aws-appmesh/test/integ.mesh.ts @@ -59,6 +59,10 @@ router.addRoute('route-1', { match: { prefixPath: '/', }, + timeout: { + idle: cdk.Duration.seconds(10), + perRequest: cdk.Duration.seconds(10), + }, }), }); @@ -118,6 +122,10 @@ router.addRoute('route-2', { match: { prefixPath: '/path2', }, + timeout: { + idle: cdk.Duration.seconds(11), + perRequest: cdk.Duration.seconds(11), + }, }), }); @@ -129,6 +137,9 @@ router.addRoute('route-3', { weight: 20, }, ], + timeout: { + idle: cdk.Duration.seconds(12), + }, }), }); diff --git a/packages/@aws-cdk/aws-appmesh/test/test.route.ts b/packages/@aws-cdk/aws-appmesh/test/test.route.ts index 2fd03f907f236..cb5c92e6464cf 100644 --- a/packages/@aws-cdk/aws-appmesh/test/test.route.ts +++ b/packages/@aws-cdk/aws-appmesh/test/test.route.ts @@ -29,6 +29,10 @@ export = { virtualNode: node, }, ], + timeout: { + idle: cdk.Duration.seconds(10), + perRequest: cdk.Duration.seconds(11), + }, }), }); @@ -39,6 +43,10 @@ export = { virtualNode: node, }, ], + timeout: { + idle: cdk.Duration.seconds(12), + perRequest: cdk.Duration.seconds(13), + }, }), }); @@ -49,6 +57,9 @@ export = { virtualNode: node, }, ], + timeout: { + idle: cdk.Duration.seconds(14), + }, }), }); @@ -62,6 +73,10 @@ export = { match: { serviceName: 'test.svc.local', }, + timeout: { + idle: cdk.Duration.seconds(15), + perRequest: cdk.Duration.seconds(16), + }, }), }); @@ -85,6 +100,16 @@ export = { Match: { Prefix: '/', }, + Timeout: { + Idle: { + Value: 10000, + Unit: 'ms', + }, + PerRequest: { + Value: 11000, + Unit: 'ms', + }, + }, }, }, RouteName: 'test-http-route', @@ -109,6 +134,16 @@ export = { Match: { Prefix: '/', }, + Timeout: { + Idle: { + Value: 12000, + Unit: 'ms', + }, + PerRequest: { + Value: 13000, + Unit: 'ms', + }, + }, }, }, RouteName: 'test-http2-route', @@ -130,6 +165,12 @@ export = { }, ], }, + Timeout: { + Idle: { + Value: 14000, + Unit: 'ms', + }, + }, }, }, RouteName: 'test-tcp-route', @@ -154,6 +195,16 @@ export = { Match: { ServiceName: 'test.svc.local', }, + Timeout: { + Idle: { + Value: 15000, + Unit: 'ms', + }, + PerRequest: { + Value: 16000, + Unit: 'ms', + }, + }, }, }, RouteName: 'test-grpc-route', @@ -188,6 +239,10 @@ export = { match: { prefixPath: '/node', }, + timeout: { + idle: cdk.Duration.seconds(10), + perRequest: cdk.Duration.seconds(11), + }, }), }); @@ -211,6 +266,16 @@ export = { Match: { Prefix: '/node', }, + Timeout: { + Idle: { + Value: 10000, + Unit: 'ms', + }, + PerRequest: { + Value: 11000, + Unit: 'ms', + }, + }, }, }, RouteName: 'test-http-route',