From 1eb41f32dc880ec437702e1054c07fda5b7d3786 Mon Sep 17 00:00:00 2001 From: Jose Diaz-Gonzalez Date: Sun, 2 Feb 2025 22:27:13 -0500 Subject: [PATCH] feat: only redeploy formations that have had their values changed Rather than redeploy every formation, only deploy formations that have had their values changed from the defaults. This still doesn't handle the case where we touch existing processes when scaling _up_, but should decrease the number of services touched otherwise during scaling. Also note that there are no tests for this new behavior yet (tests incoming). Refs #7396 --- plugins/ps/functions.go | 78 ++++++++++++++++++++++++++++++--------- plugins/ps/subcommands.go | 8 +++- plugins/ps/triggers.go | 8 +++- 3 files changed, 75 insertions(+), 19 deletions(-) diff --git a/plugins/ps/functions.go b/plugins/ps/functions.go index 3bb7f1235..b6af4f6dc 100644 --- a/plugins/ps/functions.go +++ b/plugins/ps/functions.go @@ -247,33 +247,77 @@ func scaleReport(appName string) error { return nil } -func scaleSet(appName string, skipDeploy bool, clearExisting bool, processTuples []string) error { - formations, err := parseProcessTuples(processTuples) +// scaleSetInput is the input for the scaleSet function +type scaleSetInput struct { + // appName is the name of the app to scale + appName string + + // skipDeploy is a flag to skip the deploy phase + skipDeploy bool + + // clearExisting is a flag to clear the existing scale + clearExisting bool + + // processTuples is a list of process tuples to scale + processTuples []string + + // deployOnlyChanged is a flag to deploy only the changed formations + deployOnlyChanged bool +} + +func scaleSet(input scaleSetInput) error { + existingFormations, err := getFormations(input.appName) if err != nil { return err } - if err := updateScale(appName, clearExisting, formations); err != nil { - return err - } - - if skipDeploy { - return nil - } - - if !common.IsDeployed(appName) { - return nil - } - - imageTag, err := common.GetRunningImageTag(appName, "") + formations, err := parseProcessTuples(input.processTuples) if err != nil { return err } - for _, formation := range formations { + if err := updateScale(input.appName, input.clearExisting, formations); err != nil { + return err + } + + if input.skipDeploy { + return nil + } + + if !common.IsDeployed(input.appName) { + return nil + } + + imageTag, err := common.GetRunningImageTag(input.appName, "") + if err != nil { + return err + } + + changedFormations := FormationSlice{} + if input.deployOnlyChanged { + for _, formation := range formations { + isChanged := true + for _, existingFormation := range existingFormations { + if existingFormation.ProcessType == formation.ProcessType { + if existingFormation.Quantity == formation.Quantity { + isChanged = false + break + } + } + } + + if isChanged { + changedFormations = append(changedFormations, formation) + } + } + } else { + changedFormations = formations + } + + for _, formation := range changedFormations { _, err := common.CallPlugnTrigger(common.PlugnTriggerInput{ Trigger: "deploy", - Args: []string{appName, imageTag, formation.ProcessType}, + Args: []string{input.appName, imageTag, formation.ProcessType}, StreamStdio: true, }) if err != nil { diff --git a/plugins/ps/subcommands.go b/plugins/ps/subcommands.go index 6c5882e5e..783a26161 100644 --- a/plugins/ps/subcommands.go +++ b/plugins/ps/subcommands.go @@ -160,7 +160,13 @@ func CommandScale(appName string, skipDeploy bool, processTuples []string) error } common.LogInfo1(fmt.Sprintf("Scaling %s processes: %s", appName, strings.Join(processTuples, " "))) - return scaleSet(appName, skipDeploy, false, processTuples) + return scaleSet(scaleSetInput{ + appName: appName, + skipDeploy: skipDeploy, + clearExisting: false, + processTuples: processTuples, + deployOnlyChanged: true, + }) } // CommandSet sets or clears a ps property for an app diff --git a/plugins/ps/triggers.go b/plugins/ps/triggers.go index 90a4e001b..4d788827c 100644 --- a/plugins/ps/triggers.go +++ b/plugins/ps/triggers.go @@ -339,7 +339,13 @@ func TriggerPsCurrentScale(appName string) error { // TriggerPsSetScale configures the scale parameters for a given app func TriggerPsSetScale(appName string, skipDeploy bool, clearExisting bool, processTuples []string) error { - return scaleSet(appName, skipDeploy, clearExisting, processTuples) + return scaleSet(scaleSetInput{ + appName: appName, + skipDeploy: skipDeploy, + clearExisting: clearExisting, + processTuples: processTuples, + deployOnlyChanged: false, + }) } func TriggerPsGetProperty(appName string, property string) error {