diff --git a/temporalcli/commands.gen.go b/temporalcli/commands.gen.go index eee204100..714c94950 100644 --- a/temporalcli/commands.gen.go +++ b/temporalcli/commands.gen.go @@ -3121,6 +3121,7 @@ type TemporalWorkerDeploymentSetCurrentVersionCommand struct { Command cobra.Command DeploymentVersionOrUnversionedOptions IgnoreMissingTaskQueues bool + AllowNoPollers bool Yes bool } @@ -3137,6 +3138,7 @@ func NewTemporalWorkerDeploymentSetCurrentVersionCommand(cctx *CommandContext, p } s.Command.Args = cobra.NoArgs s.Command.Flags().BoolVar(&s.IgnoreMissingTaskQueues, "ignore-missing-task-queues", false, "Override protection to accidentally remove task queues.") + s.Command.Flags().BoolVar(&s.AllowNoPollers, "allow-no-pollers", false, "Override protection and set version as current even if it has no pollers.") s.Command.Flags().BoolVarP(&s.Yes, "yes", "y", false, "Don't prompt to confirm set Current Version.") s.DeploymentVersionOrUnversionedOptions.buildFlags(cctx, s.Command.Flags()) s.Command.Run = func(c *cobra.Command, args []string) { @@ -3154,6 +3156,7 @@ type TemporalWorkerDeploymentSetRampingVersionCommand struct { Percentage float32 Delete bool IgnoreMissingTaskQueues bool + AllowNoPollers bool Yes bool } @@ -3172,6 +3175,7 @@ func NewTemporalWorkerDeploymentSetRampingVersionCommand(cctx *CommandContext, p s.Command.Flags().Float32Var(&s.Percentage, "percentage", 0, "Percentage of tasks redirected to the Ramping Version. Valid range [0,100].") s.Command.Flags().BoolVar(&s.Delete, "delete", false, "Delete the Ramping Version.") s.Command.Flags().BoolVar(&s.IgnoreMissingTaskQueues, "ignore-missing-task-queues", false, "Override protection to accidentally remove task queues.") + s.Command.Flags().BoolVar(&s.AllowNoPollers, "allow-no-pollers", false, "Override protection and set version as ramping even if it has no pollers.") s.Command.Flags().BoolVarP(&s.Yes, "yes", "y", false, "Don't prompt to confirm set Ramping Version.") s.DeploymentVersionOrUnversionedOptions.buildFlags(cctx, s.Command.Flags()) s.Command.Run = func(c *cobra.Command, args []string) { diff --git a/temporalcli/commands.worker.deployment.go b/temporalcli/commands.worker.deployment.go index a86a4c907..a742cbd9e 100644 --- a/temporalcli/commands.worker.deployment.go +++ b/temporalcli/commands.worker.deployment.go @@ -1,12 +1,14 @@ package temporalcli import ( + "errors" "fmt" "time" "github.com/fatih/color" "github.com/temporalio/cli/temporalcli/internal/printer" "go.temporal.io/api/common/v1" + "go.temporal.io/api/serviceerror" "go.temporal.io/sdk/client" "go.temporal.io/sdk/worker" ) @@ -619,7 +621,7 @@ func (c *TemporalWorkerDeploymentSetCurrentVersionCommand) run(cctx *CommandCont safeModeMessage: "Current", deploymentName: c.DeploymentName, }) - if err != nil { + if err != nil && !(errors.As(err, new(*serviceerror.NotFound)) && c.AllowNoPollers) { return err } @@ -628,6 +630,7 @@ func (c *TemporalWorkerDeploymentSetCurrentVersionCommand) run(cctx *CommandCont BuildID: c.BuildId, Identity: c.Parent.Parent.Identity, IgnoreMissingTaskQueues: c.IgnoreMissingTaskQueues, + AllowNoPollers: c.AllowNoPollers, ConflictToken: token, }) if err != nil { @@ -650,7 +653,7 @@ func (c *TemporalWorkerDeploymentSetRampingVersionCommand) run(cctx *CommandCont safeModeMessage: "Ramping", deploymentName: c.DeploymentName, }) - if err != nil { + if err != nil && !(errors.As(err, new(*serviceerror.NotFound)) && c.AllowNoPollers) { return err } @@ -666,6 +669,7 @@ func (c *TemporalWorkerDeploymentSetRampingVersionCommand) run(cctx *CommandCont ConflictToken: token, Identity: c.Parent.Parent.Identity, IgnoreMissingTaskQueues: c.IgnoreMissingTaskQueues, + AllowNoPollers: c.AllowNoPollers, }) if err != nil { return fmt.Errorf("error setting the ramping worker deployment version: %w", err) diff --git a/temporalcli/commands.worker.deployment_test.go b/temporalcli/commands.worker.deployment_test.go index 7a526b285..0311ae298 100644 --- a/temporalcli/commands.worker.deployment_test.go +++ b/temporalcli/commands.worker.deployment_test.go @@ -173,6 +173,133 @@ func (s *SharedServerSuite) TestDeployment_Set_Current_Version() { s.Nil(jsonVersionOut.Metadata) } +func (s *SharedServerSuite) TestDeployment_Set_Current_Version_AllowNoPollers() { + deploymentName := uuid.NewString() + buildId := uuid.NewString() + version := worker.WorkerDeploymentVersion{ + DeploymentName: deploymentName, + BuildID: buildId, + } + + // with --allow-no-pollers, no need to have a worker polling on this version + res := s.Execute( + "worker", "deployment", "set-current-version", + "--address", s.Address(), + "--deployment-name", version.DeploymentName, "--build-id", version.BuildID, + "--allow-no-pollers", + "--yes", + ) + s.NoError(res.Err) + + s.EventuallyWithT(func(t *assert.CollectT) { + res := s.Execute( + "worker", "deployment", "list", + "--address", s.Address(), + ) + assert.NoError(t, res.Err) + assert.Contains(t, res.Stdout.String(), deploymentName) + }, 30*time.Second, 100*time.Millisecond) + + s.EventuallyWithT(func(t *assert.CollectT) { + res := s.Execute( + "worker", "deployment", "describe-version", + "--address", s.Address(), + "--deployment-name", version.DeploymentName, "--build-id", version.BuildID, + ) + assert.NoError(t, res.Err) + }, 30*time.Second, 100*time.Millisecond) + + res = s.Execute( + "worker", "deployment", "describe", + "--address", s.Address(), + "--name", deploymentName, + ) + s.NoError(res.Err) + + s.ContainsOnSameLine(res.Stdout.String(), "Name", deploymentName) + s.ContainsOnSameLine(res.Stdout.String(), "CurrentVersionDeploymentName", version.DeploymentName) + s.ContainsOnSameLine(res.Stdout.String(), "CurrentVersionBuildID", version.BuildID) + + // json + res = s.Execute( + "worker", "deployment", "describe", + "--address", s.Address(), + "--name", deploymentName, + "--output", "json", + ) + s.NoError(res.Err) + + var jsonOut jsonDeploymentInfoType + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal(deploymentName, jsonOut.Name) + s.Equal(version.DeploymentName, jsonOut.RoutingConfig.CurrentVersionDeploymentName) + s.Equal(version.BuildID, jsonOut.RoutingConfig.CurrentVersionBuildID) +} + +func (s *SharedServerSuite) TestDeployment_Set_Ramping_Version_AllowNoPollers() { + deploymentName := uuid.NewString() + buildId := uuid.NewString() + version := worker.WorkerDeploymentVersion{ + DeploymentName: deploymentName, + BuildID: buildId, + } + + // with --allow-no-pollers, no need to have a worker polling on this version + res := s.Execute( + "worker", "deployment", "set-ramping-version", + "--address", s.Address(), + "--deployment-name", version.DeploymentName, "--build-id", version.BuildID, + "--percentage", "5", + "--allow-no-pollers", + "--yes", + ) + s.NoError(res.Err) + + s.EventuallyWithT(func(t *assert.CollectT) { + res := s.Execute( + "worker", "deployment", "list", + "--address", s.Address(), + ) + assert.NoError(t, res.Err) + assert.Contains(t, res.Stdout.String(), deploymentName) + }, 30*time.Second, 100*time.Millisecond) + + s.EventuallyWithT(func(t *assert.CollectT) { + res := s.Execute( + "worker", "deployment", "describe-version", + "--address", s.Address(), + "--deployment-name", version.DeploymentName, "--build-id", version.BuildID, + ) + assert.NoError(t, res.Err) + }, 30*time.Second, 100*time.Millisecond) + + res = s.Execute( + "worker", "deployment", "describe", + "--address", s.Address(), + "--name", deploymentName, + ) + s.NoError(res.Err) + + s.ContainsOnSameLine(res.Stdout.String(), "Name", deploymentName) + s.ContainsOnSameLine(res.Stdout.String(), "RampingVersionDeploymentName", version.DeploymentName) + s.ContainsOnSameLine(res.Stdout.String(), "RampingVersionBuildID", version.BuildID) + + // json + res = s.Execute( + "worker", "deployment", "describe", + "--address", s.Address(), + "--name", deploymentName, + "--output", "json", + ) + s.NoError(res.Err) + + var jsonOut jsonDeploymentInfoType + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal(deploymentName, jsonOut.Name) + s.Equal(version.DeploymentName, jsonOut.RoutingConfig.RampingVersionDeploymentName) + s.Equal(version.BuildID, jsonOut.RoutingConfig.RampingVersionBuildID) +} + func filterByNamePrefix(jsonOut []jsonDeploymentInfoType, prefix string) []jsonDeploymentInfoType { result := []jsonDeploymentInfoType{} for i := range jsonOut { diff --git a/temporalcli/commandsgen/commands.yml b/temporalcli/commandsgen/commands.yml index 8d1a738fd..6aeef5bc6 100644 --- a/temporalcli/commandsgen/commands.yml +++ b/temporalcli/commandsgen/commands.yml @@ -1137,6 +1137,9 @@ commands: - name: ignore-missing-task-queues type: bool description: Override protection to accidentally remove task queues. + - name: allow-no-pollers + type: bool + description: Override protection and set version as current even if it has no pollers. - name: yes short: y type: bool @@ -1204,6 +1207,9 @@ commands: - name: ignore-missing-task-queues type: bool description: Override protection to accidentally remove task queues. + - name: allow-no-pollers + type: bool + description: Override protection and set version as ramping even if it has no pollers. - name: yes short: y type: bool