Fix scaling adjustment edge case (#782)

* Update GH actions build

Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>

* Fix scaling adjustment edge case

Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>

---------

Signed-off-by: Mikkel Oscar Lyderik Larsen <mikkel.larsen@zalando.de>
This commit is contained in:
Mikkel Oscar Lyderik Larsen
2025-01-29 10:58:33 +01:00
committed by GitHub
parent 4204daa44f
commit d416441688
3 changed files with 21 additions and 8 deletions

View File

@ -10,10 +10,10 @@ jobs:
tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version: '^1.19'
go-version: '^1.23'
- run: go version
- run: go install github.com/mattn/goveralls@latest
- run: go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

View File

@ -266,13 +266,13 @@ func (c *Controller) adjustHPAScaling(ctx context.Context, hpa *autoscalingv2.Ho
return nil
}
highestExpected, highestObject := highestActiveSchedule(hpa, activeSchedules)
highestExpected, usageRatio, highestObject := highestActiveSchedule(hpa, activeSchedules, current)
highestExpected = int64(math.Min(float64(highestExpected), float64(hpa.Spec.MaxReplicas)))
var change float64
if highestExpected > current {
change = (float64(highestExpected) - float64(current)) / float64(current)
change = math.Abs(1.0 - usageRatio)
}
if change > 0 && change <= c.hpaTolerance {
@ -304,8 +304,9 @@ func (c *Controller) adjustHPAScaling(ctx context.Context, hpa *autoscalingv2.Ho
// highestActiveSchedule returns the highest active schedule value and
// corresponding object.
func highestActiveSchedule(hpa *autoscalingv2.HorizontalPodAutoscaler, activeSchedules map[string]int64) (int64, autoscalingv2.CrossVersionObjectReference) {
func highestActiveSchedule(hpa *autoscalingv2.HorizontalPodAutoscaler, activeSchedules map[string]int64, currentReplicas int64) (int64, float64, autoscalingv2.CrossVersionObjectReference) {
var highestExpected int64
var usageRatio float64
var highestObject autoscalingv2.CrossVersionObjectReference
for _, metric := range hpa.Spec.Metrics {
if metric.Type != autoscalingv2.ObjectMetricSourceType {
@ -340,11 +341,12 @@ func highestActiveSchedule(hpa *autoscalingv2.HorizontalPodAutoscaler, activeSch
expected := int64(math.Ceil(float64(value) / float64(target)))
if expected > highestExpected {
highestExpected = expected
usageRatio = float64(value) / (float64(target) * float64(currentReplicas))
highestObject = metric.Object.DescribedObject
}
}
return highestExpected, highestObject
return highestExpected, usageRatio, highestObject
}
func (c *Controller) adjustScaling(ctx context.Context, schedules []v1.ScalingScheduler) error {

View File

@ -337,24 +337,35 @@ func TestAdjustScaling(t *testing.T) {
currentReplicas int32
desiredReplicas int32
targetValue int64
scheduleTarget int64
}{
{
msg: "current less than 10%% below desired (target 10000)",
currentReplicas: 28, // 7.1% increase to desired
desiredReplicas: 31,
targetValue: 333, // 10000/333 ~= 31
scheduleTarget: 10000,
},
{
msg: "current less than 10%% below desired",
currentReplicas: 95, // 5.3% increase to desired
desiredReplicas: 100,
targetValue: 10, // 1000/10 = 100
scheduleTarget: 1000,
},
{
msg: "current more than 10%% below desired, no adjustment",
currentReplicas: 90, // 11% increase to desired
desiredReplicas: 90,
targetValue: 10, // 1000/10 = 100
scheduleTarget: 1000,
},
{
msg: "invalid HPA should not do any adjustment",
currentReplicas: 95,
desiredReplicas: 95,
targetValue: 0, // this is treated as invalid in the test, thus the HPA is ingored and no adjustment happens.
scheduleTarget: 1000,
},
} {
t.Run(tc.msg, func(t *testing.T) {
@ -384,7 +395,7 @@ func TestAdjustScaling(t *testing.T) {
Type: v1.OneTimeSchedule,
Date: &scheduleDate,
DurationMinutes: 15,
Value: 1000,
Value: tc.scheduleTarget,
},
},
},