1+ import * as cdk from '@aws-cdk/core' ;
12import { CfnRoute } from './appmesh.generated' ;
23import { Protocol , HttpTimeout , GrpcTimeout , TcpTimeout } from './shared-interfaces' ;
34import { IVirtualNode } from './virtual-node' ;
@@ -68,6 +69,81 @@ export interface HttpRouteSpecOptions {
6869 * @default - None
6970 */
7071 readonly timeout ?: HttpTimeout ;
72+
73+ /**
74+ * The retry policy
75+ *
76+ * @default - no retry policy
77+ */
78+ readonly retryPolicy ?: HttpRetryPolicy ;
79+ }
80+
81+ /**
82+ * HTTP retry policy
83+ */
84+ export interface HttpRetryPolicy {
85+ /**
86+ * Specify HTTP events on which to retry. You must specify at least one value
87+ * for at least one types of retry events.
88+ *
89+ * @default - no retries for http events
90+ */
91+ readonly httpRetryEvents ?: HttpRetryEvent [ ] ;
92+
93+ /**
94+ * The maximum number of retry attempts
95+ */
96+ readonly retryAttempts : number ;
97+
98+ /**
99+ * The timeout for each retry attempt
100+ */
101+ readonly retryTimeout : cdk . Duration ;
102+
103+ /**
104+ * TCP events on which to retry. The event occurs before any processing of a
105+ * request has started and is encountered when the upstream is temporarily or
106+ * permanently unavailable. You must specify at least one value for at least
107+ * one types of retry events.
108+ *
109+ * @default - no retries for tcp events
110+ */
111+ readonly tcpRetryEvents ?: TcpRetryEvent [ ] ;
112+ }
113+
114+ /**
115+ * HTTP events on which to retry.
116+ */
117+ export enum HttpRetryEvent {
118+ /**
119+ * HTTP status codes 500, 501, 502, 503, 504, 505, 506, 507, 508, 510, and 511
120+ */
121+ SERVER_ERROR = 'server-error' ,
122+
123+ /**
124+ * HTTP status codes 502, 503, and 504
125+ */
126+ GATEWAY_ERROR = 'gateway-error' ,
127+
128+ /**
129+ * HTTP status code 409
130+ */
131+ CLIENT_ERROR = 'client-error' ,
132+
133+ /**
134+ * Retry on refused stream
135+ */
136+ STREAM_ERROR = 'stream-error' ,
137+ }
138+
139+ /**
140+ * TCP events on which you may retry
141+ */
142+ export enum TcpRetryEvent {
143+ /**
144+ * A connection error
145+ */
146+ CONNECTION_ERROR = 'connection-error' ,
71147}
72148
73149/**
@@ -107,6 +183,64 @@ export interface GrpcRouteSpecOptions {
107183 * List of targets that traffic is routed to when a request matches the route
108184 */
109185 readonly weightedTargets : WeightedTarget [ ] ;
186+
187+ /**
188+ * The retry policy
189+ *
190+ * @default - no retry policy
191+ */
192+ readonly retryPolicy ?: GrpcRetryPolicy ;
193+ }
194+
195+ /** gRPC retry policy */
196+ export interface GrpcRetryPolicy extends HttpRetryPolicy {
197+ /**
198+ * gRPC events on which to retry. You must specify at least one value
199+ * for at least one types of retry events.
200+ *
201+ * @default - no retries for gRPC events
202+ */
203+ readonly grpcRetryEvents ?: GrpcRetryEvent [ ] ;
204+ }
205+
206+ /**
207+ * gRPC events
208+ */
209+ export enum GrpcRetryEvent {
210+ /**
211+ * Request was cancelled
212+ *
213+ * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html
214+ */
215+ CANCELLED = 'cancelled' ,
216+
217+ /**
218+ * The deadline was exceeded
219+ *
220+ * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html
221+ */
222+ DEADLINE_EXCEEDED = 'deadline-exceeded' ,
223+
224+ /**
225+ * Internal error
226+ *
227+ * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html
228+ */
229+ INTERNAL_ERROR = 'internal' ,
230+
231+ /**
232+ * A resource was exhausted
233+ *
234+ * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html
235+ */
236+ RESOURCE_EXHAUSTED = 'resource-exhausted' ,
237+
238+ /**
239+ * The service is unavailable
240+ *
241+ * @see https://grpc.github.io/grpc/core/md_doc_statuscodes.html
242+ */
243+ UNAVAILABLE = 'unavailable' ,
110244}
111245
112246/**
@@ -203,19 +337,40 @@ class HttpRouteSpec extends RouteSpec {
203337 */
204338 public readonly weightedTargets : WeightedTarget [ ] ;
205339
340+ /**
341+ * The retry policy
342+ */
343+ public readonly retryPolicy ?: HttpRetryPolicy ;
344+
206345 constructor ( props : HttpRouteSpecOptions , protocol : Protocol ) {
207346 super ( ) ;
208347 this . protocol = protocol ;
209348 this . match = props . match ;
210349 this . weightedTargets = props . weightedTargets ;
211350 this . timeout = props . timeout ;
351+
352+ if ( props . retryPolicy ) {
353+ const httpRetryEvents = props . retryPolicy . httpRetryEvents ?? [ ] ;
354+ const tcpRetryEvents = props . retryPolicy . tcpRetryEvents ?? [ ] ;
355+
356+ if ( httpRetryEvents . length + tcpRetryEvents . length === 0 ) {
357+ throw new Error ( 'You must specify one value for at least one of `httpRetryEvents` or `tcpRetryEvents`' ) ;
358+ }
359+
360+ this . retryPolicy = {
361+ ...props . retryPolicy ,
362+ httpRetryEvents : httpRetryEvents . length > 0 ? httpRetryEvents : undefined ,
363+ tcpRetryEvents : tcpRetryEvents . length > 0 ? tcpRetryEvents : undefined ,
364+ } ;
365+ }
212366 }
213367
214368 public bind ( _scope : Construct ) : RouteSpecConfig {
215369 const prefixPath = this . match ? this . match . prefixPath : '/' ;
216370 if ( prefixPath [ 0 ] != '/' ) {
217371 throw new Error ( `Prefix Path must start with \'/\', got: ${ prefixPath } ` ) ;
218372 }
373+
219374 const httpConfig : CfnRoute . HttpRouteProperty = {
220375 action : {
221376 weightedTargets : renderWeightedTargets ( this . weightedTargets ) ,
@@ -224,6 +379,7 @@ class HttpRouteSpec extends RouteSpec {
224379 prefix : prefixPath ,
225380 } ,
226381 timeout : renderTimeout ( this . timeout ) ,
382+ retryPolicy : this . retryPolicy ? renderHttpRetryPolicy ( this . retryPolicy ) : undefined ,
227383 } ;
228384 return {
229385 httpRouteSpec : this . protocol === Protocol . HTTP ? httpConfig : undefined ,
@@ -266,11 +422,33 @@ class GrpcRouteSpec extends RouteSpec {
266422 public readonly match : GrpcRouteMatch ;
267423 public readonly timeout ?: GrpcTimeout ;
268424
425+ /**
426+ * The retry policy.
427+ */
428+ public readonly retryPolicy ?: GrpcRetryPolicy ;
429+
269430 constructor ( props : GrpcRouteSpecOptions ) {
270431 super ( ) ;
271432 this . weightedTargets = props . weightedTargets ;
272433 this . match = props . match ;
273434 this . timeout = props . timeout ;
435+
436+ if ( props . retryPolicy ) {
437+ const grpcRetryEvents = props . retryPolicy . grpcRetryEvents ?? [ ] ;
438+ const httpRetryEvents = props . retryPolicy . httpRetryEvents ?? [ ] ;
439+ const tcpRetryEvents = props . retryPolicy . tcpRetryEvents ?? [ ] ;
440+
441+ if ( grpcRetryEvents . length + httpRetryEvents . length + tcpRetryEvents . length === 0 ) {
442+ throw new Error ( 'You must specify one value for at least one of `grpcRetryEvents`, `httpRetryEvents` or `tcpRetryEvents`' ) ;
443+ }
444+
445+ this . retryPolicy = {
446+ ...props . retryPolicy ,
447+ grpcRetryEvents : grpcRetryEvents . length > 0 ? grpcRetryEvents : undefined ,
448+ httpRetryEvents : httpRetryEvents . length > 0 ? httpRetryEvents : undefined ,
449+ tcpRetryEvents : tcpRetryEvents . length > 0 ? tcpRetryEvents : undefined ,
450+ } ;
451+ }
274452 }
275453
276454 public bind ( _scope : Construct ) : RouteSpecConfig {
@@ -283,6 +461,7 @@ class GrpcRouteSpec extends RouteSpec {
283461 serviceName : this . match . serviceName ,
284462 } ,
285463 timeout : renderTimeout ( this . timeout ) ,
464+ retryPolicy : this . retryPolicy ? renderGrpcRetryPolicy ( this . retryPolicy ) : undefined ,
286465 } ,
287466 } ;
288467 }
@@ -323,3 +502,22 @@ function renderTimeout(timeout?: HttpTimeout): CfnRoute.HttpTimeoutProperty | un
323502 }
324503 : undefined ;
325504}
505+
506+ function renderHttpRetryPolicy ( retryPolicy : HttpRetryPolicy ) : CfnRoute . HttpRetryPolicyProperty {
507+ return {
508+ maxRetries : retryPolicy . retryAttempts ,
509+ perRetryTimeout : {
510+ unit : 'ms' ,
511+ value : retryPolicy . retryTimeout . toMilliseconds ( ) ,
512+ } ,
513+ httpRetryEvents : retryPolicy . httpRetryEvents ,
514+ tcpRetryEvents : retryPolicy . tcpRetryEvents ,
515+ } ;
516+ }
517+
518+ function renderGrpcRetryPolicy ( retryPolicy : GrpcRetryPolicy ) : CfnRoute . GrpcRetryPolicyProperty {
519+ return {
520+ ...renderHttpRetryPolicy ( retryPolicy ) ,
521+ grpcRetryEvents : retryPolicy . grpcRetryEvents ,
522+ } ;
523+ }
0 commit comments