From fc81db490748e718a6eb735ed30710eb38d96c00 Mon Sep 17 00:00:00 2001 From: mani-j9 Date: Tue, 20 Oct 2026 14:30:16 -0700 Subject: [PATCH] Add --region-id to compute-config scaling groups --- go.mod | 4 +- go.sum | 8 +-- internal/temporalcli/commands.activity.go | 2 +- internal/temporalcli/commands.gen.go | 14 +++--- .../temporalcli/commands.worker.deployment.go | 3 +- ...rker.deployment.version.aws_lambda_test.go | 44 ++++++++++++++++ .../commands.worker.deployment.version.go | 27 +++++++--- ...commands.worker.deployment.version_test.go | 40 +++++++++++++++ internal/temporalcli/commands.yaml | 50 +++++++++++++++++-- 9 files changed, 167 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index 36f681f3f..576b4c8cb 100644 --- a/go.mod +++ b/go.mod @@ -17,8 +17,8 @@ require ( github.com/stretchr/testify v1.12.1 github.com/temporalio/cli/cliext v0.0.0 github.com/temporalio/ui-server/v2 v2.54.1 - go.temporal.io/api v1.63.5 - go.temporal.io/sdk v1.47.0 + go.temporal.io/api v1.64.0 + go.temporal.io/sdk v1.49.0 go.temporal.io/sdk/contrib/envconfig v1.0.2 go.temporal.io/server v1.32.0 golang.org/x/exp v0.0.0-20260611194520-c48552f49976 diff --git a/go.sum b/go.sum index ac3d58173..86e6aebe4 100644 --- a/go.sum +++ b/go.sum @@ -481,12 +481,12 @@ go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/ go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE= go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= -go.temporal.io/api v1.63.5 h1:c11+kPYHkXXL3UiShPdbMD+xtvqGsbTibUA9ypmiCa4= -go.temporal.io/api v1.63.5/go.mod h1:SrlW2JMwVlDP4nRWSNznUFqnSHd+YeMDS1BkYo63HCQ= +go.temporal.io/api v1.64.0 h1:Wu7TMdVN/4KdU+v0As6SMm86uapnM1yI7PhC5Hvhqso= +go.temporal.io/api v1.64.0/go.mod h1:acM0I9WPuYg8W3Pd9jOZvEgi7mRUttUQ4+e7fowKVnM= go.temporal.io/auto-scaled-workers v0.2.0-1.32.0.158.0 h1:l+Rj0cIHMC2VB/DC+axrLLnZ2ISTgUpUw8TMiP4B9F8= go.temporal.io/auto-scaled-workers v0.2.0-1.32.0.158.0/go.mod h1:ZGNY7kCU0EZpXx02D81/jGXHbUcFcVIzzguJ/f8pvUQ= -go.temporal.io/sdk v1.47.0 h1:lZ39w1+uWSjHTL0F3mSc0t4XUnKX8CCcWxqSiLbaHnc= -go.temporal.io/sdk v1.47.0/go.mod h1:ilKs0twgP4JpP8pfhIgZumnOEyBiYn6ZO/ta//NnKMU= +go.temporal.io/sdk v1.49.0 h1:CtGI0BUe/SCo3eoqTwuWWtXKueii9GBVus7KrKKH1Vo= +go.temporal.io/sdk v1.49.0/go.mod h1:xP0FulN5JJSfisESUP60LlWsrKz2tLSStGjVdk8r5cc= go.temporal.io/sdk/contrib/envconfig v1.0.2 h1:MGHfsuPUtsf7X9M6WYn3zYJj/mWsuYHnA1uuiL0KEuE= go.temporal.io/sdk/contrib/envconfig v1.0.2/go.mod h1:MuMiH7hksps2uXnmKuAWaP9P6WbkSDy62kl64t1VJVg= go.temporal.io/server v1.32.0 h1:JQoqsVREaGc8vcuDNfuRlySiV3tVi81XUOVC9LeL/1Y= diff --git a/internal/temporalcli/commands.activity.go b/internal/temporalcli/commands.activity.go index 3a53a90f7..15bb87fa4 100644 --- a/internal/temporalcli/commands.activity.go +++ b/internal/temporalcli/commands.activity.go @@ -155,7 +155,7 @@ func buildStartActivityOptions(opts *ActivityStartOptions) (client.StartActivity HeartbeatTimeout: opts.HeartbeatTimeout.Duration(), StartDelay: opts.StartDelay.Duration(), Summary: opts.StaticSummary, - Details: opts.StaticDetails, + StaticDetails: opts.StaticDetails, Priority: temporal.Priority{ PriorityKey: opts.PriorityKey, FairnessKey: opts.FairnessKey, diff --git a/internal/temporalcli/commands.gen.go b/internal/temporalcli/commands.gen.go index aafab742e..f5fc59e98 100644 --- a/internal/temporalcli/commands.gen.go +++ b/internal/temporalcli/commands.gen.go @@ -124,12 +124,14 @@ func (v *DeploymentVersionOptions) BuildFlags(f *pflag.FlagSet) { type ScalingGroupOptions struct { ScalingGroup string + RegionId string FlagSet *pflag.FlagSet } func (v *ScalingGroupOptions) BuildFlags(f *pflag.FlagSet) { v.FlagSet = f f.StringVar(&v.ScalingGroup, "scaling-group", "default", "Key of the scaling group.") + f.StringVar(&v.RegionId, "region-id", "", "Region in which this scaling group is used, such as \"aws-us-east-1\". The scaling group is only used while the Namespace is active in this region. A Version can have at most one scaling group per region, and one scaling group without a region, which is used in the regions that have none. When updating a scaling group, the region passed replaces its existing one. A scaling group's region cannot be removed; to make it the scaling group without a region, remove it and add it again without this flag.") } type AwsAssumeRoleOptions struct { @@ -4289,9 +4291,9 @@ func NewTemporalWorkerDeploymentVersionComputeConfigCommand(cctx *CommandContext s.Command.Use = "compute-config" s.Command.Short = "Set, update, or remove compute configuration for a Version (Experimental)" if hasHighlighting { - s.Command.Long = "A Worker Deployment Version's compute configuration is made of one\nor more scaling groups. Each scaling group is identified by a key\nand is made of a compute provider that starts Workers and a scaler\nthat decides when to start them. Each compute provider has its own\ncommand, such as \x1b[1maws-lambda\x1b[0m, to create and update scaling groups:\n\n\x1b[1mtemporal worker deployment version compute-config [command] [options]\x1b[0m\n\nNote: This is an experimental feature and may change in the future." + s.Command.Long = "A Worker Deployment Version's compute configuration is made of one\nor more scaling groups. Each scaling group is identified by a key\nand is made of a compute provider that starts Workers, a scaler that\ndecides when to start them, and optionally the region it is used in.\nEach compute provider has its own command, such as \x1b[1maws-lambda\x1b[0m, to\ncreate and update scaling groups:\n\n\x1b[1mtemporal worker deployment version compute-config [command] [options]\x1b[0m\n\nNote: This is an experimental feature and may change in the future." } else { - s.Command.Long = "A Worker Deployment Version's compute configuration is made of one\nor more scaling groups. Each scaling group is identified by a key\nand is made of a compute provider that starts Workers and a scaler\nthat decides when to start them. Each compute provider has its own\ncommand, such as `aws-lambda`, to create and update scaling groups:\n\n```\ntemporal worker deployment version compute-config [command] [options]\n```\n\nNote: This is an experimental feature and may change in the future." + s.Command.Long = "A Worker Deployment Version's compute configuration is made of one\nor more scaling groups. Each scaling group is identified by a key\nand is made of a compute provider that starts Workers, a scaler that\ndecides when to start them, and optionally the region it is used in.\nEach compute provider has its own command, such as `aws-lambda`, to\ncreate and update scaling groups:\n\n```\ntemporal worker deployment version compute-config [command] [options]\n```\n\nNote: This is an experimental feature and may change in the future." } s.Command.Args = cobra.NoArgs s.Command.AddCommand(&NewTemporalWorkerDeploymentVersionComputeConfigAwsLambdaCommand(cctx, &s).Command) @@ -4374,9 +4376,9 @@ func NewTemporalWorkerDeploymentVersionComputeConfigAwsLambdaUpdateCommand(cctx s.Command.Use = "update [flags]" s.Command.Short = "Update AWS Lambda compute configuration for a Version (Experimental)" if hasHighlighting { - s.Command.Long = "Update a scaling group in the compute configuration of a Worker\nDeployment Version, for an AWS Lambda function that spawns a Worker in\nthe Worker Deployment. Only the scaling group named by --scaling-group\n(\"default\" when unset) changes; other scaling groups are not affected.\n\nTo update the AWS Lambda function and the AWS IAM role associated with\nan existing Worker Deployment Version:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\x1b[0m\n\nTo update only the scaler of an existing scaling group, supply the\nscaler flags without the provider flags. The scaler is replaced as a\nwhole, so scaler flags that are not passed go back to their\ndefaults:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scale-up-backlog-threshold 5 \\\n --max-worker-lifetime-ms 300000\x1b[0m\n\nThe provider flags are --function-arn, --assume-role-arn,\n--assume-role-external-id, and --skip-role-and-external-id. The\nscaler flags are the --scale-up-* and --suppress-* flags,\n--max-worker-lifetime-ms, and --metrics-poll-interval-ms. The\nprovider flags are only needed when changing the compute provider,\nand they must be passed together: --function-arn with either both\nrole flags or --skip-role-and-external-id. Changing the provider\nalso resets the scaler: scaler flags passed with it are applied, and\nthe rest, or all of them if none are passed, go back to their\ndefaults.\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error. To create it, use\n\x1b[1mtemporal worker deployment version compute-config aws-lambda create\x1b[0m.\n\nReturns an error if all compute configuration fields are empty.\n\nNote: This is an experimental feature and may change in the future." + s.Command.Long = "Update a scaling group in the compute configuration of a Worker\nDeployment Version, for an AWS Lambda function that spawns a Worker in\nthe Worker Deployment. Only the scaling group named by --scaling-group\n(\"default\" when unset) changes; other scaling groups are not affected.\n\nTo update the AWS Lambda function and the AWS IAM role associated with\nan existing Worker Deployment Version:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\x1b[0m\n\nTo update only the scaler of an existing scaling group, supply the\nscaler flags without the provider flags. The scaler is replaced as a\nwhole, so scaler flags that are not passed go back to their\ndefaults:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scale-up-backlog-threshold 5 \\\n --max-worker-lifetime-ms 300000\x1b[0m\n\nTo add a scaling group that is only used while the Namespace is\nactive in one region:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup \\\n --region-id aws-us-east-1 \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\x1b[0m\n\nTo update only the region of a scaling group, supply --region-id\nwithout the other flags. The region passed replaces the existing\none, and the provider and scaler are not changed:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup \\\n --region-id aws-us-west-2\x1b[0m\n\nThe provider flags are --function-arn, --assume-role-arn,\n--assume-role-external-id, and --skip-role-and-external-id. The\nscaler flags are the --scale-up-* and --suppress-* flags,\n--max-worker-lifetime-ms, and --metrics-poll-interval-ms. The\nprovider flags are only needed when changing the compute provider,\nand they must be passed together: --function-arn with either both\nrole flags or --skip-role-and-external-id. Changing the provider\nalso resets the scaler: scaler flags passed with it are applied, and\nthe rest, or all of them if none are passed, go back to their\ndefaults. --region-id can be passed with any of these, and the\nregion passed replaces the existing one.\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error. To create it, use\n\x1b[1mtemporal worker deployment version compute-config aws-lambda create\x1b[0m.\n\nReturns an error if all compute configuration fields are empty.\n\nNote: This is an experimental feature and may change in the future." } else { - s.Command.Long = "Update a scaling group in the compute configuration of a Worker\nDeployment Version, for an AWS Lambda function that spawns a Worker in\nthe Worker Deployment. Only the scaling group named by --scaling-group\n(\"default\" when unset) changes; other scaling groups are not affected.\n\nTo update the AWS Lambda function and the AWS IAM role associated with\nan existing Worker Deployment Version:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\n```\n\nTo update only the scaler of an existing scaling group, supply the\nscaler flags without the provider flags. The scaler is replaced as a\nwhole, so scaler flags that are not passed go back to their\ndefaults:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scale-up-backlog-threshold 5 \\\n --max-worker-lifetime-ms 300000\n```\n\nThe provider flags are --function-arn, --assume-role-arn,\n--assume-role-external-id, and --skip-role-and-external-id. The\nscaler flags are the --scale-up-* and --suppress-* flags,\n--max-worker-lifetime-ms, and --metrics-poll-interval-ms. The\nprovider flags are only needed when changing the compute provider,\nand they must be passed together: --function-arn with either both\nrole flags or --skip-role-and-external-id. Changing the provider\nalso resets the scaler: scaler flags passed with it are applied, and\nthe rest, or all of them if none are passed, go back to their\ndefaults.\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error. To create it, use\n`temporal worker deployment version compute-config aws-lambda create`.\n\nReturns an error if all compute configuration fields are empty.\n\nNote: This is an experimental feature and may change in the future." + s.Command.Long = "Update a scaling group in the compute configuration of a Worker\nDeployment Version, for an AWS Lambda function that spawns a Worker in\nthe Worker Deployment. Only the scaling group named by --scaling-group\n(\"default\" when unset) changes; other scaling groups are not affected.\n\nTo update the AWS Lambda function and the AWS IAM role associated with\nan existing Worker Deployment Version:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\n```\n\nTo update only the scaler of an existing scaling group, supply the\nscaler flags without the provider flags. The scaler is replaced as a\nwhole, so scaler flags that are not passed go back to their\ndefaults:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scale-up-backlog-threshold 5 \\\n --max-worker-lifetime-ms 300000\n```\n\nTo add a scaling group that is only used while the Namespace is\nactive in one region:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup \\\n --region-id aws-us-east-1 \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\n```\n\nTo update only the region of a scaling group, supply --region-id\nwithout the other flags. The region passed replaces the existing\none, and the provider and scaler are not changed:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup \\\n --region-id aws-us-west-2\n```\n\nThe provider flags are --function-arn, --assume-role-arn,\n--assume-role-external-id, and --skip-role-and-external-id. The\nscaler flags are the --scale-up-* and --suppress-* flags,\n--max-worker-lifetime-ms, and --metrics-poll-interval-ms. The\nprovider flags are only needed when changing the compute provider,\nand they must be passed together: --function-arn with either both\nrole flags or --skip-role-and-external-id. Changing the provider\nalso resets the scaler: scaler flags passed with it are applied, and\nthe rest, or all of them if none are passed, go back to their\ndefaults. --region-id can be passed with any of these, and the\nregion passed replaces the existing one.\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error. To create it, use\n`temporal worker deployment version compute-config aws-lambda create`.\n\nReturns an error if all compute configuration fields are empty.\n\nNote: This is an experimental feature and may change in the future." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVar(&s.FunctionArn, "function-arn", "", "Qualified (contains version suffix) or unqualified AWS Lambda function ARN to invoke when there are no active pollers for task queue targets in the Worker Deployment. Required when changing the compute provider.") @@ -4405,9 +4407,9 @@ func NewTemporalWorkerDeploymentVersionComputeConfigDescribeCommand(cctx *Comman s.Command.Use = "describe [flags]" s.Command.Short = "Show the compute configuration of a Version (Experimental)" if hasHighlighting { - s.Command.Long = "Show the scaling groups in the compute configuration of a Worker\nDeployment Version, with their compute provider and scaler settings:\n\n\x1b[1mtemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\x1b[0m\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error.\n\nNote: This is an experimental feature and may change in the future." + s.Command.Long = "Show the scaling groups in the compute configuration of a Worker\nDeployment Version, with their region, compute provider, and scaler\nsettings:\n\n\x1b[1mtemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\x1b[0m\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error.\n\nNote: This is an experimental feature and may change in the future." } else { - s.Command.Long = "Show the scaling groups in the compute configuration of a Worker\nDeployment Version, with their compute provider and scaler settings:\n\n```\ntemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\n```\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error.\n\nNote: This is an experimental feature and may change in the future." + s.Command.Long = "Show the scaling groups in the compute configuration of a Worker\nDeployment Version, with their region, compute provider, and scaler\nsettings:\n\n```\ntemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\n```\n\nIf a Worker Deployment Version with the supplied BuildID does not exist,\nthis command will return an error.\n\nNote: This is an experimental feature and may change in the future." } s.Command.Args = cobra.NoArgs s.DeploymentVersionOptions.BuildFlags(s.Command.Flags()) diff --git a/internal/temporalcli/commands.worker.deployment.go b/internal/temporalcli/commands.worker.deployment.go index 90b682918..1f201901c 100644 --- a/internal/temporalcli/commands.worker.deployment.go +++ b/internal/temporalcli/commands.worker.deployment.go @@ -130,6 +130,7 @@ type formattedComputeConfig struct { } type formattedComputeConfigScalingGroup struct { + RegionId string `json:"regionId,omitempty"` Provider *formattedComputeConfigProvider `json:"provider,omitempty"` Scaler *formattedComputeConfigScaler `json:"scaler,omitempty"` } @@ -518,7 +519,7 @@ func formatComputeConfigProto(cc *computepb.ComputeConfig) *formattedComputeConf if p == nil && s == nil { continue } - sg := formattedComputeConfigScalingGroup{} + sg := formattedComputeConfigScalingGroup{RegionId: strings.Join(msgSG.GetRegionIds(), ", ")} if p != nil { sg.Provider = &formattedComputeConfigProvider{ Type: p.GetType(), diff --git a/internal/temporalcli/commands.worker.deployment.version.aws_lambda_test.go b/internal/temporalcli/commands.worker.deployment.version.aws_lambda_test.go index 8b2730e08..492eae37a 100644 --- a/internal/temporalcli/commands.worker.deployment.version.aws_lambda_test.go +++ b/internal/temporalcli/commands.worker.deployment.version.aws_lambda_test.go @@ -163,6 +163,33 @@ func (s *SharedServerSuite) TestComputeConfig_AwsLambda_UpdateError() { s.ErrorContains(res.Err, "error updating worker deployment version compute config: invalid compute config") } +func (s *SharedServerSuite) TestComputeConfig_AwsLambda_RegionID() { + fake := s.newFakeComputeConfigServer() + fake.setComputeConfig(nil) + deploymentName := uuid.NewString() + + // A new scaling group gets the region, and the mask covers it. + res := s.Execute(lambdaComputeConfigArgs("update", s.Address(), deploymentName, + "--scaling-group", "aws-us-east-1", "--region-id", "aws-us-east-1")...) + s.NoError(res.Err) + s.Empty(res.Stderr.String()) + updates := fake.takeUpdates() + s.Len(updates, 1) + update := updates[0].GetComputeConfigScalingGroups()["aws-us-east-1"] + s.Equal([]string{"aws-us-east-1"}, update.GetScalingGroup().GetRegionIds()) + s.Equal([]string{"region_ids", "provider.type", "provider.details", "scaler.type", "scaler.details"}, update.GetUpdateMask().GetPaths()) + + // Leaving out --region-id keeps the region. + res = s.Execute(lambdaComputeConfigArgs("update", s.Address(), deploymentName, "--scaling-group", "aws-us-east-1")...) + s.NoError(res.Err) + updates = fake.takeUpdates() + s.Len(updates, 1) + update = updates[0].GetComputeConfigScalingGroups()["aws-us-east-1"] + s.Empty(update.GetScalingGroup().GetRegionIds()) + s.NotContains(update.GetUpdateMask().GetPaths(), "region_ids") + s.Equal([]string{"aws-us-east-1"}, fake.computeConfig.GetScalingGroups()["aws-us-east-1"].GetRegionIds()) +} + func (s *SharedServerSuite) TestComputeConfig_AwsLambda_ScalerSettings() { fake := s.newFakeComputeConfigServer() fake.versionMissing = true @@ -243,6 +270,16 @@ func (s *SharedServerSuite) TestComputeConfig_AwsLambda_PartialUpdate() { s.Equal("no-sync", sg.GetScaler().GetType()) s.Equal(map[string]any{"scale_up_cooloff_ms": float64(500)}, s.decodePayloadMap(sg.GetScaler().GetDetails())) s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_ACTIVITY}, sg.GetTaskQueueTypes()) + s.Equal([]string{"aws-us-west-2"}, sg.GetRegionIds()) + + // --region-id on its own changes only the region. + res = s.Execute(args("--scaling-group", "aws-us-east-1-wf", "--region-id", "aws-us-west-2")...) + s.NoError(res.Err) + s.Equal([]string{"region_ids"}, onlyUpdate("aws-us-east-1-wf").GetUpdateMask().GetPaths()) + sg = stored("aws-us-east-1-wf") + s.Equal([]string{"aws-us-west-2"}, sg.GetRegionIds()) + s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_WORKFLOW}, sg.GetTaskQueueTypes()) + s.Equal("aws-lambda", sg.GetProvider().GetType()) // The provider flags replace the provider and reset the scaling settings to // the scaling flags passed with them, which here are none. @@ -256,6 +293,7 @@ func (s *SharedServerSuite) TestComputeConfig_AwsLambda_PartialUpdate() { s.Equal("no-sync", sg.GetScaler().GetType()) s.Nil(sg.GetScaler().GetDetails()) s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_ACTIVITY}, sg.GetTaskQueueTypes()) + s.Equal([]string{"aws-us-west-2"}, sg.GetRegionIds()) // The provider flags are passed together, and something must be passed. for _, tc := range []struct { @@ -336,6 +374,12 @@ func (s *SharedServerSuite) TestComputeConfig_Provider_Errors() { "--function-arn", "arn", "--skip-role-and-external-id", "--scaling-group", ""), errText: "--scaling-group cannot be empty", }, + { + name: "empty region ID", + args: append(append([]string{}, lambda...), + "--function-arn", "arn", "--skip-role-and-external-id", "--region-id", ""), + errText: "--region-id cannot be empty", + }, } { res := s.Execute(tc.args...) s.ErrorContains(res.Err, tc.errText, tc.name) diff --git a/internal/temporalcli/commands.worker.deployment.version.go b/internal/temporalcli/commands.worker.deployment.version.go index 9d3e0af78..7df44046d 100644 --- a/internal/temporalcli/commands.worker.deployment.version.go +++ b/internal/temporalcli/commands.worker.deployment.version.go @@ -111,6 +111,7 @@ func (c *TemporalWorkerDeploymentVersionComputeConfigDescribeCommand) run(cctx * type scalingGroupCard struct { ScalingGroup string + RegionId string `cli:",cardOmitEmpty"` Provider string `cli:",cardOmitEmpty"` Scaler string `cli:",cardOmitEmpty"` } @@ -118,7 +119,7 @@ func (c *TemporalWorkerDeploymentVersionComputeConfigDescribeCommand) run(cctx * cards := make([]scalingGroupCard, 0, len(keys)) for _, key := range keys { sg := described.ScalingGroups[key] - card := scalingGroupCard{ScalingGroup: key} + card := scalingGroupCard{ScalingGroup: key, RegionId: sg.RegionId} if sg.Provider != nil { card.Provider = sg.Provider.Type } @@ -215,13 +216,20 @@ func (c *TemporalWorkerDeploymentVersionComputeConfigRemoveCommand) run(cctx *Co } // scalingGroup builds the provider-independent part of a scaling group from -// the --scaling-group flag. Scaling groups set from the CLI serve every Task -// Queue type. +// the --scaling-group and --region-id flags. Scaling groups set from the CLI +// serve every Task Queue type. func (o *ScalingGroupOptions) scalingGroup() (*computepb.ComputeConfigScalingGroup, error) { if o.ScalingGroup == "" { return nil, fmt.Errorf("--scaling-group cannot be empty") } - return &computepb.ComputeConfigScalingGroup{}, nil + sg := &computepb.ComputeConfigScalingGroup{} + if o.FlagSet.Changed("region-id") { + if o.RegionId == "" { + return nil, fmt.Errorf("--region-id cannot be empty") + } + sg.RegionIds = []string{o.RegionId} + } + return sg, nil } // update builds the provider-independent part of a scaling group update: the @@ -231,7 +239,11 @@ func (o *ScalingGroupOptions) update() (*computepb.ComputeConfigScalingGroup, [] if err != nil { return nil, nil, err } - return sg, nil, nil + var paths []string + if o.FlagSet.Changed("region-id") { + paths = append(paths, "region_ids") + } + return sg, paths, nil } // createVersionWithScalingGroup creates a Worker Deployment Version with one @@ -417,6 +429,7 @@ type formattedComputeConfigDescription struct { } type formattedScalingGroupDescription struct { + RegionId string `json:"regionId,omitempty"` Provider *formattedComputeConfigProvider `json:"provider,omitempty"` Scaler *formattedScalerDescription `json:"scaler,omitempty"` } @@ -436,7 +449,9 @@ type formattedScalerDescription struct { func formatComputeConfigDescription(cc *computepb.ComputeConfig) formattedComputeConfigDescription { out := formattedComputeConfigDescription{ScalingGroups: map[string]formattedScalingGroupDescription{}} for name, msgSG := range cc.GetScalingGroups() { - var sg formattedScalingGroupDescription + // The CLI sets one region; a scaling group set through the API may have + // several, which are shown together. + sg := formattedScalingGroupDescription{RegionId: strings.Join(msgSG.GetRegionIds(), ", ")} if p := msgSG.GetProvider(); p != nil { sg.Provider = &formattedComputeConfigProvider{Type: p.GetType()} } diff --git a/internal/temporalcli/commands.worker.deployment.version_test.go b/internal/temporalcli/commands.worker.deployment.version_test.go index 9aab2e110..6fcfe1e14 100644 --- a/internal/temporalcli/commands.worker.deployment.version_test.go +++ b/internal/temporalcli/commands.worker.deployment.version_test.go @@ -95,6 +95,8 @@ func (f *fakeComputeConfigServer) update(key string, update *computepb.ComputeCo src := update.GetScalingGroup() for _, path := range update.GetUpdateMask().GetPaths() { switch path { + case "region_ids": + merged.RegionIds = src.GetRegionIds() case "provider.type", "provider.details": if merged.Provider == nil { merged.Provider = &computepb.ComputeProvider{} @@ -212,11 +214,13 @@ func twoScalingGroupComputeConfig() *computepb.ComputeConfig { ScalingGroups: map[string]*computepb.ComputeConfigScalingGroup{ "aws-us-west-2-ac": { TaskQueueTypes: []enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_ACTIVITY}, + RegionIds: []string{"aws-us-west-2"}, Provider: &computepb.ComputeProvider{Type: "aws-lambda"}, Scaler: &computepb.ComputeScaler{Type: "no-sync", Details: scalerDetails}, }, "aws-us-east-1-wf": { TaskQueueTypes: []enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_WORKFLOW}, + RegionIds: []string{"aws-us-east-1"}, Provider: &computepb.ComputeProvider{Type: "aws-lambda"}, Scaler: &computepb.ComputeScaler{Type: "no-sync"}, }, @@ -254,10 +258,12 @@ func (s *SharedServerSuite) TestComputeConfig_Describe() { // Like describe-version, the Task Queue types are not shown. s.NotContains(groups, "TaskQueueTypes") s.ContainsOnSameLine(cards[0], "ScalingGroup", "aws-us-east-1-wf") + s.ContainsOnSameLine(cards[0], "RegionId", "aws-us-east-1") s.ContainsOnSameLine(cards[0], "Provider", "aws-lambda") s.ContainsOnSameLine(cards[0], "Scaler", "no-sync") s.NotContains(cards[0], "(") s.ContainsOnSameLine(cards[1], "ScalingGroup", "aws-us-west-2-ac") + s.ContainsOnSameLine(cards[1], "RegionId", "aws-us-west-2") s.ContainsOnSameLine(cards[1], "Scaler", "no-sync (scale_up_backlog_threshold 2, max_worker_lifetime_ms 300000, scale_up_dispatch_rate_epsilon 0.05)") @@ -265,6 +271,7 @@ func (s *SharedServerSuite) TestComputeConfig_Describe() { s.NoError(res.Err) var described struct { ScalingGroups map[string]struct { + RegionId string `json:"regionId"` Provider struct { Type string `json:"type"` } `json:"provider"` @@ -281,9 +288,11 @@ func (s *SharedServerSuite) TestComputeConfig_Describe() { s.NoError(json.Unmarshal(res.Stdout.Bytes(), &described)) s.Len(described.ScalingGroups, 2) wf := described.ScalingGroups["aws-us-east-1-wf"] + s.Equal("aws-us-east-1", wf.RegionId) s.Equal("aws-lambda", wf.Provider.Type) s.Equal("no-sync", wf.Scaler.Type) ac := described.ScalingGroups["aws-us-west-2-ac"] + s.Equal("aws-us-west-2", ac.RegionId) s.Equal("aws-lambda", ac.Provider.Type) s.Equal("no-sync", ac.Scaler.Type) // The no-sync settings that are set are shown; the others are left out. @@ -489,6 +498,37 @@ func (s *SharedServerSuite) TestVersion_Describe_MatchesDescribeVersion() { s.Empty(fake.takeUpdates()) } +func (s *SharedServerSuite) TestVersion_Describe_Regions() { + fake := s.newFakeComputeConfigServer() + cc := twoScalingGroupComputeConfig() + cc.ScalingGroups["default"] = &computepb.ComputeConfigScalingGroup{ + Provider: &computepb.ComputeProvider{Type: "aws-lambda"}, + Scaler: &computepb.ComputeScaler{Type: "no-sync"}, + } + fake.setComputeConfig(cc) + args := []string{"worker", "deployment", "version", "describe", "--address", s.Address(), "--deployment-name", "d", "--build-id", "b"} + + // The text summary is unchanged: one entry per provider. + res := s.Execute(args...) + s.NoError(res.Err) + s.ContainsOnSameLine(res.Stdout.String(), "ComputeConfigSummary", "aws-lambda") + s.NotContains(res.Stdout.String(), "aws-us-east-1") + + // Scaling groups with a region show it; the one without a region does not. + res = s.Execute(append(args, "-o", "json")...) + s.NoError(res.Err) + var described struct { + ComputeConfig struct { + ScalingGroups map[string]map[string]any `json:"scalingGroups"` + } `json:"computeConfig"` + } + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &described)) + groups := described.ComputeConfig.ScalingGroups + s.Equal("aws-us-east-1", groups["aws-us-east-1-wf"]["regionId"]) + s.Equal("aws-us-west-2", groups["aws-us-west-2-ac"]["regionId"]) + s.NotContains(groups["default"], "regionId") +} + // TestVersion_CreateDescribeDelete runs against the real server, with a Version // that has no compute config. func (s *SharedServerSuite) TestVersion_CreateDescribeDelete() { diff --git a/internal/temporalcli/commands.yaml b/internal/temporalcli/commands.yaml index 3d2d83dfc..1800a06f2 100644 --- a/internal/temporalcli/commands.yaml +++ b/internal/temporalcli/commands.yaml @@ -1955,9 +1955,10 @@ commands: description: | A Worker Deployment Version's compute configuration is made of one or more scaling groups. Each scaling group is identified by a key - and is made of a compute provider that starts Workers and a scaler - that decides when to start them. Each compute provider has its own - command, such as `aws-lambda`, to create and update scaling groups: + and is made of a compute provider that starts Workers, a scaler that + decides when to start them, and optionally the region it is used in. + Each compute provider has its own command, such as `aws-lambda`, to + create and update scaling groups: ``` temporal worker deployment version compute-config [command] [options] @@ -1969,7 +1970,8 @@ commands: summary: Show the compute configuration of a Version (Experimental) description: | Show the scaling groups in the compute configuration of a Worker - Deployment Version, with their compute provider and scaler settings: + Deployment Version, with their region, compute provider, and scaler + settings: ``` temporal worker deployment version compute-config describe \ @@ -2084,6 +2086,32 @@ commands: --max-worker-lifetime-ms 300000 ``` + To add a scaling group that is only used while the Namespace is + active in one region: + + ``` + temporal worker deployment version compute-config aws-lambda update \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --scaling-group YourScalingGroup \ + --region-id aws-us-east-1 \ + --function-arn YourLambdaFunctionARN \ + --assume-role-arn YourAssumeRoleARN \ + --assume-role-external-id YourExternalID + ``` + + To update only the region of a scaling group, supply --region-id + without the other flags. The region passed replaces the existing + one, and the provider and scaler are not changed: + + ``` + temporal worker deployment version compute-config aws-lambda update \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --scaling-group YourScalingGroup \ + --region-id aws-us-west-2 + ``` + The provider flags are --function-arn, --assume-role-arn, --assume-role-external-id, and --skip-role-and-external-id. The scaler flags are the --scale-up-* and --suppress-* flags, @@ -2093,7 +2121,8 @@ commands: role flags or --skip-role-and-external-id. Changing the provider also resets the scaler: scaler flags passed with it are applied, and the rest, or all of them if none are passed, go back to their - defaults. + defaults. --region-id can be passed with any of these, and the + region passed replaces the existing one. If a Worker Deployment Version with the supplied BuildID does not exist, this command will return an error. To create it, use @@ -5765,6 +5794,17 @@ option-sets: default: default description: | Key of the scaling group. + - name: region-id + type: string + description: | + Region in which this scaling group is used, such as + "aws-us-east-1". The scaling group is only used while the Namespace + is active in this region. A Version can have at most one scaling + group per region, and one scaling group without a region, which is + used in the regions that have none. When updating a scaling group, + the region passed replaces its existing one. A scaling group's + region cannot be removed; to make it the scaling group without a + region, remove it and add it again without this flag. - name: aws-assume-role options: