Skip to content

Conversation

zahorniak
Copy link

@zahorniak zahorniak commented Oct 6, 2025

Description

  • Added support for predefined metrics

    • predefined_load_metric_specification
    • predefined_metric_pair_specification
    • predefined_scaling_metric_specification
  • Added support for customized metrics

    • customized_capacity_metric_specification
    • customized_load_metric_specification
    • customized_scaling_metric_specification

Motivation and Context

Breaking Changes

No

How Has This Been Tested?

  • I have updated at least one of the examples/* to demonstrate and validate my change(s)
  • I have tested and validated these changes using one or more of the provided examples/* projects
  • I have executed pre-commit run -a on my pull request

@zahorniak
Copy link
Author

I want to address a naming inconsistency across target_tracking_scaling_policy_configuration.customized_metric_specification.dimensions and customized_*_specification.metric_data_query.metric_stat.metric.dimension:

Target tracking using dimensionS while all predictive scaling metrics use dimension naming. In the module configuration, I decided to use dimensions everywhere to keep the same object structure as you already have for target tracking policies:

metrics = optional(list(object({
  expression = optional(string)
  id         = string
  label      = optional(string)
  metric_stat = optional(object({
    metric = object({
      dimensions = optional(list(object({
        name  = string
        value = string
      })))
      metric_name = string
      namespace   = string
    })
    stat = string
    unit = optional(string)
  }))
  return_data = optional(bool)
})))

I believe it can help prevent mistakes or typos when using multiple scaling policies for a single service.

@zahorniak zahorniak marked this pull request as ready for review October 6, 2025 14:34
@zahorniak zahorniak changed the title wip: Add support for predictive autoscaling feat: Add support for predictive autoscaling policies Oct 6, 2025
@bryantbiggs
Copy link
Member

I want to address a naming inconsistency across target_tracking_scaling_policy_configuration.customized_metric_specification.dimensions and customized_*_specification.metric_data_query.metric_stat.metric.dimension:

* [registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy#dimensions-1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy#dimensions-1)

* [registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy#dimension-1](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy#dimension-1)

Target tracking using dimensionS while all predictive scaling metrics use dimension naming. In the module configuration, I decided to use dimensions everywhere to keep the same object structure as you already have for target tracking policies:

metrics = optional(list(object({
  expression = optional(string)
  id         = string
  label      = optional(string)
  metric_stat = optional(object({
    metric = object({
      dimensions = optional(list(object({
        name  = string
        value = string
      })))
      metric_name = string
      namespace   = string
    })
    stat = string
    unit = optional(string)
  }))
  return_data = optional(bool)
})))

I believe it can help prevent mistakes or typos when using multiple scaling policies for a single service.

thats due to the API - https://github.com/hashicorp/terraform-provider-aws/blob/782cca0e2343caa5ee37950708d563ef25a95aa7/internal/service/appautoscaling/policy.go#L249

vs https://github.com/hashicorp/terraform-provider-aws/blob/782cca0e2343caa5ee37950708d563ef25a95aa7/internal/service/appautoscaling/policy.go#L451

We usually try to match the underlying API since thats the easiest and least confusing, only deviating in select scenarios

Copy link
Member

@bryantbiggs bryantbiggs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great start! few changes to the structure and definitions

}
}

dynamic "predictive_scaling_policy_configuration" {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

general comment, lets follow the order of fields on the AWS provider. It makes it easier to check and compare https://github.com/hashicorp/terraform-provider-aws/blob/782cca0e2343caa5ee37950708d563ef25a95aa7/internal/service/appautoscaling/policy.go#L67

for_each = each.value.policy_type == "PredictiveScaling" && each.value.predictive_scaling_policy_configuration != null ? [each.value.predictive_scaling_policy_configuration] : []

content {
mode = try(predictive_scaling_policy_configuration.value.mode, null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

with variable optional attributes, we can drop all the try() wrappings. you can refer to the target_tracking_scaling_policy_configuration for reference

scale_out_cooldown = optional(number, 60)
target_value = optional(number, 75)
}))
predictive_scaling_policy_configuration = optional(object({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and same here, lets follow the order of fields on the AWS provider which also follows the order of the implementation in this module

max_capacity_buffer = optional(number)
max_capacity_breach_behavior = optional(string)
scheduling_buffer_time = optional(number)
metric_specification = object({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

}))
}))
customized_scaling_metric_specification = optional(object({
metric_data_query = list(object({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

value = string
})))
metric_name = string
namespace = string
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
namespace = string
namespace = optional(string)

return_data = optional(bool)
}))
}))
customized_capacity_metric_specification = optional(object({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same type as the corrected customized_scaling_metric_specification

predefined_metric_type = string
resource_label = optional(string)
}))
customized_load_metric_specification = optional(object({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same type as the corrected customized_scaling_metric_specification

target_value = optional(number, 75)
}))
predictive_scaling_policy_configuration = optional(object({
mode = optional(string, "ForecastAndScale")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whats the reasoning behind this default value?

scale_out_cooldown = optional(number)
target_value = optional(number)
}))
predictive_scaling_policy_configuration = optional(object({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update this once the corrections to module/service/variables.tf are made

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for predictive_scaling_policy_configuration configuration block for service autoscaling
2 participants