-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(apprunner): add HealthCheckConfiguration property in Service #27029
Changes from 11 commits
b4889f8
a30062d
779a580
f346240
1415c34
9f63382
deb0418
7345fe9
877d5f2
2a11dc4
9e84888
629b131
d0cd255
70c125e
5938fd1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -706,6 +706,13 @@ export interface ServiceProps { | |
* @default - no VPC connector, uses the DEFAULT egress type instead | ||
*/ | ||
readonly vpcConnector?: IVpcConnector; | ||
|
||
/** | ||
* Settings for the health check that AWS App Runner performs to monitor the health of a service. | ||
* | ||
* @default - no health check configuration | ||
*/ | ||
readonly healthCheckConfiguration?: HealthCheckConfiguration; | ||
} | ||
|
||
/** | ||
|
@@ -848,6 +855,72 @@ export class GitHubConnection { | |
} | ||
} | ||
|
||
/** | ||
* The health check protocol type | ||
*/ | ||
export enum HealthCheckProtocolType { | ||
/** | ||
* HTTP protocol | ||
*/ | ||
HTTP = 'HTTP', | ||
|
||
/** | ||
* TCP protocol | ||
*/ | ||
TCP = 'TCP', | ||
} | ||
|
||
/** | ||
* Describes the settings for the health check that AWS App Runner performs to monitor the health of a service. | ||
*/ | ||
export interface HealthCheckConfiguration { | ||
/** | ||
* The number of consecutive checks that must succeed before App Runner decides that the service is healthy. | ||
* | ||
* @default 1 | ||
*/ | ||
readonly healthyThreshold?: number; | ||
|
||
/** | ||
* The time interval, in seconds, between health checks. | ||
* | ||
* @default Duration.seconds(5) | ||
*/ | ||
readonly interval?: cdk.Duration; | ||
|
||
/** | ||
* The URL that health check requests are sent to. | ||
* | ||
* `path` is only applicable when you set `protocol` to `HTTP`. | ||
* | ||
* @default / | ||
*/ | ||
readonly path?: string; | ||
|
||
/** | ||
* The IP protocol that App Runner uses to perform health checks for your service. | ||
* | ||
* If you set `protocol` to `HTTP`, App Runner sends health check requests to the HTTP path specified by `path`. | ||
* | ||
* @default HealthCheckProtocolType.TCP | ||
*/ | ||
readonly protocol?: HealthCheckProtocolType; | ||
|
||
/** | ||
* The time, in seconds, to wait for a health check response before deciding it failed. | ||
* | ||
* @default Duration.seconds(2) | ||
*/ | ||
readonly timeout?: cdk.Duration; | ||
|
||
/** | ||
* The number of consecutive checks that must fail before App Runner decides that the service is unhealthy. | ||
* | ||
* @default 5 | ||
*/ | ||
readonly unhealthyThreshold?: number; | ||
} | ||
|
||
/** | ||
* Attributes for the App Runner Service | ||
*/ | ||
|
@@ -1074,6 +1147,8 @@ export class Service extends cdk.Resource implements iam.IGrantable { | |
throw new Error('configurationValues cannot be provided if the ConfigurationSource is Repository'); | ||
} | ||
|
||
this.validateHealthCheckConfiguration(this.props.healthCheckConfiguration); | ||
|
||
const resource = new CfnService(this, 'Resource', { | ||
serviceName: this.props.serviceName, | ||
instanceConfiguration: { | ||
|
@@ -1097,6 +1172,9 @@ export class Service extends cdk.Resource implements iam.IGrantable { | |
vpcConnectorArn: this.props.vpcConnector?.vpcConnectorArn, | ||
}, | ||
}, | ||
healthCheckConfiguration: this.props.healthCheckConfiguration ? | ||
this.renderHealthCheckConfiguration(this.props.healthCheckConfiguration) : | ||
undefined, | ||
}); | ||
|
||
// grant required privileges for the role | ||
|
@@ -1259,4 +1337,48 @@ export class Service extends cdk.Resource implements iam.IGrantable { | |
}, | ||
}); | ||
} | ||
|
||
private renderHealthCheckConfiguration(props: HealthCheckConfiguration) { | ||
return { | ||
healthyThreshold: props.healthyThreshold, | ||
interval: props.interval?.toSeconds(), | ||
path: props.path, | ||
protocol: props.protocol, | ||
timeout: props.timeout?.toSeconds(), | ||
unhealthyThreshold: props.unhealthyThreshold, | ||
}; | ||
} | ||
|
||
private validateHealthCheckConfiguration(healthCheckConfiguration?: HealthCheckConfiguration) { | ||
if (!healthCheckConfiguration) return; | ||
|
||
if (healthCheckConfiguration.path !== undefined) { | ||
if (healthCheckConfiguration.protocol !== HealthCheckProtocolType.HTTP) { | ||
throw new Error('path is only applicable when you set Protocol to HTTP'); | ||
} | ||
if (healthCheckConfiguration.path.length === 0) { | ||
throw new Error('path length must be greater than 0'); | ||
} | ||
} | ||
if (healthCheckConfiguration.healthyThreshold !== undefined) { | ||
if (healthCheckConfiguration.healthyThreshold < 1 || healthCheckConfiguration.healthyThreshold > 20) { | ||
throw new Error(`healthyThreshold must be between 1 and 20, got ${healthCheckConfiguration.healthyThreshold}`); | ||
} | ||
} | ||
if (healthCheckConfiguration.unhealthyThreshold !== undefined) { | ||
if (healthCheckConfiguration.unhealthyThreshold < 1 || healthCheckConfiguration.unhealthyThreshold > 20) { | ||
throw new Error(`unhealthyThreshold must be between 1 and 20, got ${healthCheckConfiguration.unhealthyThreshold}`); | ||
} | ||
} | ||
if (healthCheckConfiguration.interval !== undefined) { | ||
if (healthCheckConfiguration.interval.toSeconds() < 1 || healthCheckConfiguration.interval.toSeconds() > 20) { | ||
throw new Error(`interval must be between 1 and 20 seconds, got ${healthCheckConfiguration.interval}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I changed! |
||
} | ||
} | ||
if (healthCheckConfiguration.timeout !== undefined) { | ||
if (healthCheckConfiguration.timeout.toSeconds() < 1 || healthCheckConfiguration.timeout.toSeconds() > 20) { | ||
throw new Error(`timeout must be between 1 and 20 seconds, got ${healthCheckConfiguration.timeout}`); | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
{ | ||
"Resources": { | ||
"ServiceInstanceRoleDFA90CEC": { | ||
"Type": "AWS::IAM::Role", | ||
"Properties": { | ||
"AssumeRolePolicyDocument": { | ||
"Statement": [ | ||
{ | ||
"Action": "sts:AssumeRole", | ||
"Effect": "Allow", | ||
"Principal": { | ||
"Service": "tasks.apprunner.amazonaws.com" | ||
} | ||
} | ||
], | ||
"Version": "2012-10-17" | ||
} | ||
} | ||
}, | ||
"ServiceDBC79909": { | ||
"Type": "AWS::AppRunner::Service", | ||
"Properties": { | ||
"HealthCheckConfiguration": { | ||
"HealthyThreshold": 5, | ||
"Interval": 10, | ||
"Path": "/", | ||
"Protocol": "HTTP", | ||
"Timeout": 10, | ||
"UnhealthyThreshold": 10 | ||
}, | ||
"InstanceConfiguration": { | ||
"InstanceRoleArn": { | ||
"Fn::GetAtt": [ | ||
"ServiceInstanceRoleDFA90CEC", | ||
"Arn" | ||
] | ||
} | ||
}, | ||
"NetworkConfiguration": { | ||
"EgressConfiguration": { | ||
"EgressType": "DEFAULT" | ||
} | ||
}, | ||
"SourceConfiguration": { | ||
"AuthenticationConfiguration": {}, | ||
"ImageRepository": { | ||
"ImageConfiguration": { | ||
"Port": "8000" | ||
}, | ||
"ImageIdentifier": "public.ecr.aws/aws-containers/hello-app-runner:latest", | ||
"ImageRepositoryType": "ECR_PUBLIC" | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
"Parameters": { | ||
"BootstrapVersion": { | ||
"Type": "AWS::SSM::Parameter::Value<String>", | ||
"Default": "/cdk-bootstrap/hnb659fds/version", | ||
"Description": "Version of the CDK Bootstrap resources in this environment, automatically retrieved from SSM Parameter Store. [cdk:skip]" | ||
} | ||
}, | ||
"Rules": { | ||
"CheckBootstrapVersion": { | ||
"Assertions": [ | ||
{ | ||
"Assert": { | ||
"Fn::Not": [ | ||
{ | ||
"Fn::Contains": [ | ||
[ | ||
"1", | ||
"2", | ||
"3", | ||
"4", | ||
"5" | ||
], | ||
{ | ||
"Ref": "BootstrapVersion" | ||
} | ||
] | ||
} | ||
] | ||
}, | ||
"AssertDescription": "CDK bootstrap stack version 6 required. Please run 'cdk bootstrap' with a recent version of the CDK CLI." | ||
} | ||
] | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like us to use an enum like class for this, because HTTP and TCP health checks have different props:
Have a look at
appmesh.HealthCheck
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mrgrain
I changed to use the
HealthCheck
class likeappmesh.HealthCheck
.d0cd255
70c125e