feat(elasticloadbalancingv2): support target group health attributes#33351
feat(elasticloadbalancingv2): support target group health attributes#33351mergify[bot] merged 1 commit intoaws:mainfrom
Conversation
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #33351 +/- ##
=======================================
Coverage 80.92% 80.92%
=======================================
Files 236 236
Lines 14253 14253
Branches 2490 2490
=======================================
Hits 11534 11534
Misses 2434 2434
Partials 285 285
Flags with carried forward coverage won't be shown. Click here to find out more.
|
1801d8a to
842ae26
Compare
| return ret; | ||
| } | ||
|
|
||
| private validateTargetGroupHealth(props: TargetGroupHealthAttribute) { |
There was a problem hiding this comment.
I think it's better to put these validation logic into setAttribute method.
|
|
||
| /** | ||
| * Configuring target group health. | ||
| * | ||
| * @default undefined - use default configuration | ||
| * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#target-group-attributes | ||
| */ | ||
| readonly targetGroupHealth?: TargetGroupHealthAttribute; | ||
| } | ||
|
|
||
| /** | ||
| * Properties for configuring a target group health | ||
| * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#target-group-attributes | ||
| */ | ||
| export interface TargetGroupHealthAttribute { | ||
| /** | ||
| * The minimum number of targets that must be healthy. | ||
| * If the number of healthy targets is below this value, mark the zone as unhealthy in DNS, so that traffic is routed only to healthy zones. | ||
| * The possible values are off or an integer from 1 to the maximum number of targets. | ||
| * | ||
| * @default - 0 | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetCount?: number; | ||
|
|
||
| /** | ||
| * The minimum percentage of targets that must be healthy. | ||
| * If the percentage of healthy targets is below this value, mark the zone as unhealthy in DNS, so that traffic is routed only to healthy zones. | ||
| * The possible values are off or an integer from 1 to 100. | ||
| * | ||
| * @default - 0 | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetPercentage?: number; | ||
|
|
||
| /** | ||
| * The minimum number of targets that must be healthy. | ||
| * If the number of healthy targets is below this value, send traffic to all targets, including unhealthy targets. | ||
| * The possible values are 1 to the maximum number of targets. | ||
| * | ||
| * @default - 1 | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetCount?: number; | ||
|
|
||
| /** | ||
| * The minimum percentage of targets that must be healthy. | ||
| * If the percentage of healthy targets is below this value, send traffic to all targets, including unhealthy targets. | ||
| * The possible values are off or an integer from 1 to 100. | ||
| * | ||
| * @default - 0 | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetPercentage?: number; |
There was a problem hiding this comment.
I believe what's currently missing is a flexible way to define additional attributes at the time of Construct creation. In my opinion, adding a dedicated property for every possible target group attribute is not an ideal solution, as it reduces flexibility and increases maintenance overhead.
To address this, I propose the following change:
/**
* Enum representing AWS Application Load Balancer Target Group Attributes
*
* These attributes can be used to configure target group behavior for ALBs.
* Reference: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#target-group-attributes
*/
export enum TargetGroupAttribute {
// Deregistration delay timeout in seconds (0–3600, default: 300)
DEREGISTRATION_DELAY_TIMEOUT = "deregistration_delay.timeout_seconds",
// Load balancing algorithm type (round_robin, least_outstanding_requests, weighted_random)
LOAD_BALANCING_ALGORITHM_TYPE = "load_balancing.algorithm.type",
// Anomaly mitigation for weighted_random algorithm (on, off)
LOAD_BALANCING_ALGORITHM_ANOMALY_MITIGATION = "load_balancing.algorithm.anomaly_mitigation",
// Cross-zone load balancing (true, false, use_load_balancer_configuration)
LOAD_BALANCING_CROSS_ZONE_ENABLED = "load_balancing.cross_zone.enabled",
// Slow start duration in seconds (30–900, default: 0)
SLOW_START_DURATION_SECONDS = "slow_start.duration_seconds",
// Stickiness enabled flag (true, false)
STICKINESS_ENABLED = "stickiness.enabled",
// Application cookie name
STICKINESS_APP_COOKIE_NAME = "stickiness.app_cookie.cookie_name",
// Application cookie duration in seconds (1–604800, default: 86400)
STICKINESS_APP_COOKIE_DURATION_SECONDS = "stickiness.app_cookie.duration_seconds",
// Load balancer cookie duration in seconds (1–604800, default: 86400)
STICKINESS_LB_COOKIE_DURATION_SECONDS = "stickiness.lb_cookie.duration_seconds",
// Stickiness type (lb_cookie, app_cookie)
STICKINESS_TYPE = "stickiness.type",
// Minimum healthy targets count for DNS failover (off, 1–max targets, default: 1)
TARGET_GROUP_HEALTH_DNS_FAILOVER_MIN_HEALTHY_COUNT = "target_group_health.dns_failover.minimum_healthy_targets.count",
// Minimum healthy targets percentage for DNS failover (off, 1–100, default: off)
TARGET_GROUP_HEALTH_DNS_FAILOVER_MIN_HEALTHY_PERCENTAGE = "target_group_health.dns_failover.minimum_healthy_targets.percentage",
// Minimum healthy targets count for unhealthy state routing (1–max targets, default: 1)
TARGET_GROUP_HEALTH_UNHEALTHY_ROUTING_MIN_HEALTHY_COUNT = "target_group_health.unhealthy_state_routing.minimum_healthy_targets.count",
// Minimum healthy targets percentage for unhealthy state routing (off, 1–100, default: off)
TARGET_GROUP_HEALTH_UNHEALTHY_ROUTING_MIN_HEALTHY_PERCENTAGE = "target_group_health.unhealthy_state_routing.minimum_healthy_targets.percentage",
// Lambda multi-value headers enabled flag (true, false, default: false)
LAMBDA_MULTI_VALUE_HEADERS_ENABLED = "lambda.multi_value_headers.enabled"
}
/**
* Properties for configuring an Application Load Balancer Target Group
*/
export interface TargetGroupProps {
// ... existing properties
/**
* Target group attributes.
*
* Use the TargetGroupAttribute enum for attribute keys.
*
* @example
* const targetGroup = new elbv2.ApplicationTargetGroup(this, 'MyTargetGroup', {
* // ...other properties
* attributes: {
* [elbv2.TargetGroupAttribute.DEREGISTRATION_DELAY_TIMEOUT]: '60',
* [elbv2.TargetGroupAttribute.LOAD_BALANCING_ALGORITHM_TYPE]: 'least_outstanding_requests',
* [elbv2.TargetGroupAttribute.TARGET_GROUP_HEALTH_DNS_FAILOVER_MIN_HEALTHY_COUNT]: '2',
* }
* });
*
* @default - No attributes
*/
readonly attributes?: Record<string, string>;
}Then, in the constructor, you can apply these attributes in a generic way:
props.attributes?.forEach(([k, v]) => this.setAttribute(k, v));Make sure all validation logic is encapsulated within the setAttribute method.
Example Usage
const targetGroup = new elbv2.ApplicationTargetGroup(this, 'MyTargetGroup', {
vpc,
port: 80,
protocol: elbv2.ApplicationProtocol.HTTP,
targetType: elbv2.TargetType.IP,
// Apply target group attributes using the enum
attributes: {
[elbv2.TargetGroupAttribute.SLOW_START_DURATION_SECONDS]: '60',
[elbv2.TargetGroupAttribute.STICKINESS_ENABLED]: 'true',
[elbv2.TargetGroupAttribute.STICKINESS_TYPE]: 'app_cookie',
[elbv2.TargetGroupAttribute.STICKINESS_APP_COOKIE_NAME]: 'my-app-cookie',
[elbv2.TargetGroupAttribute.STICKINESS_APP_COOKIE_DURATION_SECONDS]: '3600',
[elbv2.TargetGroupAttribute.TARGET_GROUP_HEALTH_DNS_FAILOVER_MIN_HEALTHY_COUNT]: '2',
[elbv2.TargetGroupAttribute.TARGET_GROUP_HEALTH_DNS_FAILOVER_MIN_HEALTHY_PERCENTAGE]: '60',
[elbv2.TargetGroupAttribute.TARGET_GROUP_HEALTH_UNHEALTHY_ROUTING_MIN_HEALTHY_COUNT]: '1',
[elbv2.TargetGroupAttribute.TARGET_GROUP_HEALTH_UNHEALTHY_ROUTING_MIN_HEALTHY_PERCENTAGE]: '50',
}
});This approach keeps the API surface clean, avoids bloating the TargetGroupProps interface with dozens of optional properties, and provides a flexible and extensible way to support all current and future target group attributes.
There was a problem hiding this comment.
Thank you for the detailed instruction, I can just simply copy paste most of your code.
However, IMO, there is 1 drawback of this approach: users have to input everything as a string. The new attributes is mostly the same as the current setAttribute method.
If we choose to allow only string and not number/boolean, I think we should not add the new attributes. Instead, support the new enum and add validation logic to setAttribute. Then advise user to use setAttribute. Let me know your thought on this.
There was a problem hiding this comment.
Thanks for the feedback! I agree that allowing a more flexible type for attributes could enhance the developer experience.
That said, since the current setAttribute function only accepts string values (key:string value?:string), one possible approach would be to change its signature to (key: string, value?: any) and update attributes to use Record<string, any>. We could then handle type and value validation within setAttribute, although this would introduce additional implementation complexity.
There was a problem hiding this comment.
Agree with that. Will do as discussed.
Another thing is, should we also deprecate the 2 current crossZoneEnabled, deregistrationDelay params as they serve the same purpose with upcoming attributes ? https://github.com/aws/aws-cdk/blame/842ae2658bd958be00b47cec97130fe98d348c34/packages/aws-cdk-lib/aws-elasticloadbalancingv2/lib/shared/base-target-group.ts#L76-L82
There was a problem hiding this comment.
Yeah, thanks for pointing that out. We should add the @deprecated annotation to those two options, but we shouldn’t remove them, as that would introduce a breaking change.
There was a problem hiding this comment.
Hi @5d, sorry for taking too much time to response. After trying to add that much attributes, I found that there are some misunderstanding here.
There are 3 files included: base-target-group, application-target-group and network-target-group. According to https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-elasticloadbalancingv2-targetgroup-targetgroupattribute.html, each kind of LB only support a subset of attributes.
As I'm trying to edit the base-target-group, we should only add 4 missing attributes supported by both ALB and NLB:
- target_group_health.dns_failover.minimum_healthy_targets.count
- target_group_health.dns_failover.minimum_healthy_targets.percentage
- target_group_health.unhealthy_state_routing.minimum_healthy_targets.count
- target_group_health.unhealthy_state_routing.minimum_healthy_targets.percentage
ALB-specific attributes are already supported in application-target-group.ts
Therefore, I think we should only add the 4 common attributes (and their validation) the same way as deregistrationDelay for the scope of this PR
Please let me know your thought, thanks for your time.
|
This PR has been in the CHANGES REQUESTED state for 3 weeks, and looks abandoned. Note that PRs with failing linting check or builds are not reviewed, please ensure your build is passing To prevent automatic closure:
This PR will automatically close in 14 days if no action is taken. |
3182912 to
cf89e72
Compare
17532d0 to
427ac88
Compare
AWS CodeBuild CI Report
Powered by github-codebuild-logs, available on the AWS Serverless Application Repository |
| * | ||
| * @default - 1 | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetCount?: number | string; |
There was a problem hiding this comment.
It is not possible to use Union types in CDK. See design guidelines
There was a problem hiding this comment.
Oh thanks for this, I should have checked the guideline. Let me fix it.
| * | ||
| * @default - off | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetPercentage?: number | string; |
There was a problem hiding this comment.
It is not possible to use Union types in CDK. See design guidelines
There was a problem hiding this comment.
Sure this is fixed.
| * | ||
| * @default - off | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetPercentage?: number | string; |
There was a problem hiding this comment.
It is not possible to use Union types in CDK. See design guidelines
There was a problem hiding this comment.
Sure this is fixed.
| /** | ||
| * Stickiness type for load balancers | ||
| * | ||
| * @see https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-target-groups.html#stickiness |
There was a problem hiding this comment.
Link is wrong, there is no section called stickness
There was a problem hiding this comment.
As we agreed not going with this enum, this is removed.
| /** | ||
| * The minimum number of targets that must be healthy. | ||
| * If the number of healthy targets is below this value, mark the zone as unhealthy in DNS, so that traffic is routed only to healthy zones. | ||
| * The possible values are off or an integer from 1 to the maximum number of targets. | ||
| * | ||
| * @default - 1 | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetCount?: number | string; | ||
|
|
||
| /** | ||
| * The minimum percentage of targets that must be healthy. | ||
| * If the percentage of healthy targets is below this value, mark the zone as unhealthy in DNS, so that traffic is routed only to healthy zones. | ||
| * The possible values are off or an integer from 1 to 100. | ||
| * | ||
| * @default - off | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetPercentage?: number | string; | ||
|
|
||
| /** | ||
| * The minimum number of targets that must be healthy. | ||
| * If the number of healthy targets is below this value, send traffic to all targets, including unhealthy targets. | ||
| * The possible values are 1 to the maximum number of targets. | ||
| * | ||
| * @default - 1 | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetCount?: number; | ||
|
|
||
| /** | ||
| * The minimum percentage of targets that must be healthy. | ||
| * If the percentage of healthy targets is below this value, send traffic to all targets, including unhealthy targets. | ||
| * The possible values are off or an integer from 1 to 100. | ||
| * | ||
| * @default - off | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetPercentage?: number | string; | ||
| } |
There was a problem hiding this comment.
I would prefer to design this in a different way. Since these are all related to target group health and this could include additional configs in the future, we can group them under one interface.
interface TargetGroupHealth {
/**
* The minimum number of targets that must be healthy for DNS failover.
* If below this value, mark the zone as unhealthy in DNS.
* @default 1
*/
readonly dnsFailoverMinimumHealthyTargetCount?: number;
/**
* The minimum percentage of targets that must be healthy for DNS failover.
* If below this value, mark the zone as unhealthy in DNS.
* Use 0 for "off".
* @default 0
*/
readonly dnsFailoverMinimumHealthyTargetPercentage?: number;
/**
* The minimum number of targets that must be healthy for unhealthy state routing.
* If below this value, send traffic to all targets including unhealthy ones.
* @default 1
*/
readonly unhealthyStateRoutingMinimumHealthyTargetCount?: number;
/**
* The minimum percentage of targets that must be healthy for unhealthy state routing.
* If below this value, send traffic to all targets including unhealthy ones.
* Use 0 for "off".
* @default 0
*/
readonly unhealthyStateRoutingMinimumHealthyTargetPercentage?: number;
}
We can use 0 value as an off option, since UNION is not supported
There was a problem hiding this comment.
Thank you for this. I also added the Use 0 for "off" comment for 1st prop dnsFailoverMinimumHealthyTargetCount
| * These attributes can be used to configure target group behavior for ELBs. | ||
| * Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-elasticloadbalancingv2-targetgroup-targetgroupattribute.html | ||
| */ | ||
| export enum TargetGroupAttribute { |
There was a problem hiding this comment.
Using this enum would require a big refactoring on the existing functionality. I think this design is a bit late to be decided, we can keep adding these new properties as in the current design to not create two different implementation styles. I would recommend to not add this enum
There was a problem hiding this comment.
Thanks for explaining the situation. This was me following the last review. Of course i prefer just adding props for simplicity.
There was a problem hiding this comment.
Yes, I've seen that. I think there was an initial miss (other target group classes) there as you pointed out, so we can keep it with more simple approach
427ac88 to
77b3666
Compare
Pull request has been modified.
ozelalisen
left a comment
There was a problem hiding this comment.
Thank you for your quick iteration! I have just one final suggestion which I think would make interface more clear.
| readonly dnsFailoverMinimumHealthyTargetCount?: number; | ||
|
|
||
| /** | ||
| * The minimum percentage of targets that must be healthy for DNS failover. | ||
| * If below this value, mark the zone as unhealthy in DNS. | ||
| * Use 0 for "off". | ||
| * @default 0 | ||
| */ | ||
| readonly dnsFailoverMinimumHealthyTargetPercentage?: number; | ||
|
|
||
| /** | ||
| * The minimum number of targets that must be healthy for unhealthy state routing. | ||
| * If below this value, send traffic to all targets including unhealthy ones. | ||
| * @default 1 | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetCount?: number; | ||
|
|
||
| /** | ||
| * The minimum percentage of targets that must be healthy for unhealthy state routing. | ||
| * If below this value, send traffic to all targets including unhealthy ones. | ||
| * Use 0 for "off". | ||
| * @default 0 | ||
| */ | ||
| readonly unhealthyStateRoutingMinimumHealthyTargetPercentage?: number; |
There was a problem hiding this comment.
I feel like this naming from CFN is a bit confusing. We could name these properties as:
dnsMinimumHealthyTargetCount
dnsMinimumHealthyTargetPercentage
routingMinimumHealthyTargetCount
routingMinimumHealthyTargetPercentage
I think this would make it more clear.
77b3666 to
5506710
Compare
|
Thank you for contributing! Your pull request will be updated from main and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork). |
|
Comments on closed issues and PRs are hard for our team to see. |
feat(elasticloadbalancingv2): support target group health attributes
Issue # (if applicable)
Closes #31821
Reason for this change
elasticloadbalancingv2 support target group health attributes
Description of changes
TargetGroup support 4 heatlh attributes:
target_group_health.unhealthy_state_routing.minimum_healthy_targets.percentagetarget_group_health.dns_failover.minimum_healthy_targets.percentagetarget_group_health.unhealthy_state_routing.minimum_healthy_targets.counttarget_group_health.dns_failover.minimum_healthy_targets.countCleanup setup duplication in unit test.
Describe any new or updated permissions being added
Description of how you validated changes
Unit + Integ
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license