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 574a100b5..00e8b7113 100644 --- a/internal/temporalcli/commands.gen.go +++ b/internal/temporalcli/commands.gen.go @@ -124,6 +124,7 @@ func (v *DeploymentVersionOptions) BuildFlags(f *pflag.FlagSet) { type ScalingGroupOptions struct { ScalingGroup string + RegionId []string TaskQueueType cliext.FlagStringEnumArray FlagSet *pflag.FlagSet } @@ -131,6 +132,7 @@ type ScalingGroupOptions struct { func (v *ScalingGroupOptions) BuildFlags(f *pflag.FlagSet) { v.FlagSet = f f.StringVar(&v.ScalingGroup, "scaling-group", "default", "Key of the scaling group.") + f.StringArrayVar(&v.RegionId, "region-id", nil, "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 one of these regions, and takes precedence there over scaling groups without regions. A scaling group created without this flag can be used in any region. When updating a scaling group, the regions passed replace its existing ones. Can be passed multiple times.") v.TaskQueueType = cliext.NewFlagStringEnumArray([]string{"workflow", "activity", "nexus"}, []string{}) f.Var(&v.TaskQueueType, "task-queue-type", "Task Queue type served by this scaling group. A scaling group created without this flag is a fallback for the Task Queue types that more specific scaling groups do not serve. When updating a scaling group, the types passed replace its existing ones. Can be passed multiple times. Accepted values: workflow, activity, nexus.") } @@ -3823,6 +3825,11 @@ type TemporalWorkerDeploymentCreateVersionCommand struct { AwsAgentcoreAssumeRoleArn string AwsAgentcoreAssumeRoleExternalId string AwsAgentcoreSkipRoleAndExternalId bool + ModalAppName string + ModalFunctionName string + ModalEnvironment string + ModalWorkspaceId string + ModalVersion string GcpCloudRunProject string GcpCloudRunRegion string GcpCloudRunWorkerPool string @@ -3841,9 +3848,9 @@ func NewTemporalWorkerDeploymentCreateVersionCommand(cctx *CommandContext, paren s.Command.Use = "create-version [flags]" s.Command.Short = "Create a new Worker Deployment Version" if hasHighlighting { - s.Command.Long = "\nCreate a new Worker Deployment Version:\n\n\x1b[1mtemporal worker deployment create-version [options]\x1b[0m\n\nConfigure a Worker Deployment Version's compute configuration as needed.\nFor example, pass compute provider information for an AWS Lambda function\nthat spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-lambda-function-arn LambdaFunctionARN \\\n --aws-lambda-assume-role-arn LambdaAssumeRoleARN \\\n --aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID\x1b[0m\n\nOr pass compute provider information for an AWS Bedrock Agentcore Runtime\nthat spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn AgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn AgentcoreAssumeRoleARN \\\n --aws-agentcore-assume-role-external-id AgentcoreAssumeRoleExternalID\x1b[0m\n\nOr pass compute provider information for a GCP Cloud Run worker pool\nthat spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool YourWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\x1b[0m\n\nIf a Worker Deployment Version with the supplied BuildID already exists,\nthis command will return an error.\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 = "\nCreate a new Worker Deployment Version:\n\n\x1b[1mtemporal worker deployment create-version [options]\x1b[0m\n\nConfigure a Worker Deployment Version's compute configuration as needed.\nFor example, pass compute provider information for an AWS Lambda function\nthat spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-lambda-function-arn LambdaFunctionARN \\\n --aws-lambda-assume-role-arn LambdaAssumeRoleARN \\\n --aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID\x1b[0m\n\nOr pass compute provider information for an AWS Bedrock Agentcore Runtime\nthat spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn AgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn AgentcoreAssumeRoleARN \\\n --aws-agentcore-assume-role-external-id AgentcoreAssumeRoleExternalID\x1b[0m\n\nOr pass a deployed Modal application and function that spawns a Worker in\nthe Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --modal-app-name YourModalApp \\\n --modal-function-name YourModalFunction \\\n --modal-environment main\x1b[0m\n\nOr pass compute provider information for a GCP Cloud Run worker pool\nthat spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool YourWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\x1b[0m\n\nIf a Worker Deployment Version with the supplied BuildID already exists,\nthis command will return an error.\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 = "\nCreate a new Worker Deployment Version:\n\n```\ntemporal worker deployment create-version [options]\n```\n\nConfigure a Worker Deployment Version's compute configuration as needed.\nFor example, pass compute provider information for an AWS Lambda function\nthat spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-lambda-function-arn LambdaFunctionARN \\\n --aws-lambda-assume-role-arn LambdaAssumeRoleARN \\\n --aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID\n```\n\nOr pass compute provider information for an AWS Bedrock Agentcore Runtime\nthat spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn AgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn AgentcoreAssumeRoleARN \\\n --aws-agentcore-assume-role-external-id AgentcoreAssumeRoleExternalID\n```\n\nOr pass compute provider information for a GCP Cloud Run worker pool\nthat spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool YourWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\n```\n\nIf a Worker Deployment Version with the supplied BuildID already exists,\nthis command will return an error.\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 = "\nCreate a new Worker Deployment Version:\n\n```\ntemporal worker deployment create-version [options]\n```\n\nConfigure a Worker Deployment Version's compute configuration as needed.\nFor example, pass compute provider information for an AWS Lambda function\nthat spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-lambda-function-arn LambdaFunctionARN \\\n --aws-lambda-assume-role-arn LambdaAssumeRoleARN \\\n --aws-lambda-assume-role-external-id LambdaAssumeRoleExternalID\n```\n\nOr pass compute provider information for an AWS Bedrock Agentcore Runtime\nthat spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn AgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn AgentcoreAssumeRoleARN \\\n --aws-agentcore-assume-role-external-id AgentcoreAssumeRoleExternalID\n```\n\nOr pass a deployed Modal application and function that spawns a Worker in\nthe Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --modal-app-name YourModalApp \\\n --modal-function-name YourModalFunction \\\n --modal-environment main\n```\n\nOr pass compute provider information for a GCP Cloud Run worker pool\nthat spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment create-version \\\n --namespace YourNamespaceName \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool YourWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\n```\n\nIf a Worker Deployment Version with the supplied BuildID already exists,\nthis command will return an error.\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.AwsLambdaFunctionArn, "aws-lambda-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.") @@ -3854,6 +3861,11 @@ func NewTemporalWorkerDeploymentCreateVersionCommand(cctx *CommandContext, paren s.Command.Flags().StringVar(&s.AwsAgentcoreAssumeRoleArn, "aws-agentcore-assume-role-arn", "", "AWS IAM role ARN that the Temporal server will assume when invoking the Agentcore Runtime that spawns a new Worker in this Worker Deployment Version. Required when --aws-agentcore-endpoint-arn is specified, and must be omitted when --aws-agentcore-skip-role-and-external-id is passed.") s.Command.Flags().StringVar(&s.AwsAgentcoreAssumeRoleExternalId, "aws-agentcore-assume-role-external-id", "", "Temporal server will enforce that the AWS IAM trust policy associated with the AWS IAM role specified in --aws-agentcore-assume-role-arn has an aws:ExternalId condition that matches the supplied value. Required when --aws-agentcore-endpoint-arn is specified, and must be omitted when --aws-agentcore-skip-role-and-external-id is passed.") s.Command.Flags().BoolVar(&s.AwsAgentcoreSkipRoleAndExternalId, "aws-agentcore-skip-role-and-external-id", false, "When --aws-agentcore-endpoint-arn is specified, --aws-agentcore-assume-role-arn and --aws-agentcore-assume-role-external-id are required unless this flag is passed, in which case both must be omitted.") + s.Command.Flags().StringVar(&s.ModalAppName, "modal-app-name", "", "Name of the deployed Modal application containing the Worker function. Required when configuring a Modal compute provider.") + s.Command.Flags().StringVar(&s.ModalFunctionName, "modal-function-name", "", "Name of the Modal function to invoke when there are no active pollers for task queue targets in the Worker Deployment. Required when configuring a Modal compute provider.") + s.Command.Flags().StringVar(&s.ModalEnvironment, "modal-environment", "", "Modal environment containing the deployed application. Required when configuring a Modal compute provider.") + s.Command.Flags().StringVar(&s.ModalWorkspaceId, "modal-workspace-id", "", "Optional Modal workspace ID used to select the workspace's credential grant. Omit when the server uses ambient Modal credentials.") + s.Command.Flags().StringVar(&s.ModalVersion, "modal-version", "", "Optional deployed Modal application version, expressed as a non-negative integer. Omit to use the application's current deployed version.") s.Command.Flags().StringVar(&s.GcpCloudRunProject, "gcp-cloud-run-project", "", "GCP project ID hosting the Cloud Run worker pool. Required when --gcp-cloud-run-worker-pool is specified.") s.Command.Flags().StringVar(&s.GcpCloudRunRegion, "gcp-cloud-run-region", "", "Region of the Cloud Run worker pool. Required when --gcp-cloud-run-worker-pool is specified.") s.Command.Flags().StringVar(&s.GcpCloudRunWorkerPool, "gcp-cloud-run-worker-pool", "", "GCP Cloud Run worker pool name to scale when there are no active pollers for task queue targets in the Worker Deployment.") @@ -4175,6 +4187,11 @@ type TemporalWorkerDeploymentUpdateVersionComputeConfigCommand struct { AwsAgentcoreAssumeRoleArn string AwsAgentcoreAssumeRoleExternalId string AwsAgentcoreSkipRoleAndExternalId bool + ModalAppName string + ModalFunctionName string + ModalEnvironment string + ModalWorkspaceId string + ModalVersion string GcpCloudRunProject string GcpCloudRunRegion string GcpCloudRunWorkerPool string @@ -4194,9 +4211,9 @@ func NewTemporalWorkerDeploymentUpdateVersionComputeConfigCommand(cctx *CommandC s.Command.Use = "update-version-compute-config [flags]" s.Command.Short = "Update compute configuration for a Version" if hasHighlighting { - s.Command.Long = "Update compute configuration associated with a Worker Deployment\nVersion.\n\nFor example, to update the AWS Lambda function ARN associated with an\nexisting Worker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-function-arn UpdatedLambdaFunctionARN\x1b[0m\n\nTo update the AWS IAM role ARN that is assumed by the serverless worker\nmanager associated with an existing Worker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-assume-role-arn UpdatedRoleARN\x1b[0m\n\nTo update the AWS Bedrock Agentcore Runtime endpoint associated with an\nexisting Worker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn UpdatedAgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn UpdatedRoleARN \\\n --aws-agentcore-assume-role-external-id UpdatedExternalID\x1b[0m\n\nTo update the GCP Cloud Run worker pool associated with an existing\nWorker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool UpdatedWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\x1b[0m\n\nTo update only the scaling settings on an existing GCP Cloud Run Worker\nDeployment Version, supply the five scaler flags without the provider\nfields (all five must be set together):\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\x1b[0m\n\nProvider fields are only required when changing the compute provider.\nSwitching the provider resets the scaling settings for the new provider.\n\nIf --remove is specified, the compute configuration for the Worker\nDeployment Version will be removed:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --remove\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 = "Update compute configuration associated with a Worker Deployment\nVersion.\n\nFor example, to update the AWS Lambda function ARN associated with an\nexisting Worker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-function-arn UpdatedLambdaFunctionARN\x1b[0m\n\nTo update the AWS IAM role ARN that is assumed by the serverless worker\nmanager associated with an existing Worker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-assume-role-arn UpdatedRoleARN\x1b[0m\n\nTo update the AWS Bedrock Agentcore Runtime endpoint associated with an\nexisting Worker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn UpdatedAgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn UpdatedRoleARN \\\n --aws-agentcore-assume-role-external-id UpdatedExternalID\x1b[0m\n\nTo update the Modal application and function associated with an existing\nWorker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --modal-app-name UpdatedModalApp \\\n --modal-function-name UpdatedModalFunction \\\n --modal-environment main\x1b[0m\n\nTo update the GCP Cloud Run worker pool associated with an existing\nWorker Deployment Version:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool UpdatedWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\x1b[0m\n\nTo update only the scaling settings on an existing GCP Cloud Run Worker\nDeployment Version, supply the five scaler flags without the provider\nfields (all five must be set together):\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\x1b[0m\n\nProvider fields are only required when changing the compute provider.\nSwitching the provider resets the scaling settings for the new provider.\n\nIf --remove is specified, the compute configuration for the Worker\nDeployment Version will be removed:\n\n\x1b[1m temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --remove\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 = "Update compute configuration associated with a Worker Deployment\nVersion.\n\nFor example, to update the AWS Lambda function ARN associated with an\nexisting Worker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-function-arn UpdatedLambdaFunctionARN\n```\n\nTo update the AWS IAM role ARN that is assumed by the serverless worker\nmanager associated with an existing Worker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-assume-role-arn UpdatedRoleARN\n```\n\nTo update the AWS Bedrock Agentcore Runtime endpoint associated with an\nexisting Worker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn UpdatedAgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn UpdatedRoleARN \\\n --aws-agentcore-assume-role-external-id UpdatedExternalID\n```\n\nTo update the GCP Cloud Run worker pool associated with an existing\nWorker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool UpdatedWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\n```\n\nTo update only the scaling settings on an existing GCP Cloud Run Worker\nDeployment Version, supply the five scaler flags without the provider\nfields (all five must be set together):\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\n```\n\nProvider fields are only required when changing the compute provider.\nSwitching the provider resets the scaling settings for the new provider.\n\nIf --remove is specified, the compute configuration for the Worker\nDeployment Version will be removed:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --remove\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 = "Update compute configuration associated with a Worker Deployment\nVersion.\n\nFor example, to update the AWS Lambda function ARN associated with an\nexisting Worker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-function-arn UpdatedLambdaFunctionARN\n```\n\nTo update the AWS IAM role ARN that is assumed by the serverless worker\nmanager associated with an existing Worker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-lambda-assume-role-arn UpdatedRoleARN\n```\n\nTo update the AWS Bedrock Agentcore Runtime endpoint associated with an\nexisting Worker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --aws-agentcore-endpoint-arn UpdatedAgentcoreRuntimeEndpointARN \\\n --aws-agentcore-assume-role-arn UpdatedRoleARN \\\n --aws-agentcore-assume-role-external-id UpdatedExternalID\n```\n\nTo update the Modal application and function associated with an existing\nWorker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --modal-app-name UpdatedModalApp \\\n --modal-function-name UpdatedModalFunction \\\n --modal-environment main\n```\n\nTo update the GCP Cloud Run worker pool associated with an existing\nWorker Deployment Version:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-project YourGCPProject \\\n --gcp-cloud-run-region us-central1 \\\n --gcp-cloud-run-worker-pool UpdatedWorkerPool \\\n --gcp-cloud-run-service-account customer-sa@proj.iam.gserviceaccount.com \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\n```\n\nTo update only the scaling settings on an existing GCP Cloud Run Worker\nDeployment Version, supply the five scaler flags without the provider\nfields (all five must be set together):\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --gcp-cloud-run-min-instances 1 \\\n --gcp-cloud-run-max-instances 3 \\\n --gcp-cloud-run-initial-instances 1 \\\n --gcp-cloud-run-utilization-target 0.75 \\\n --gcp-cloud-run-scale-down-stabilization-duration 5m\n```\n\nProvider fields are only required when changing the compute provider.\nSwitching the provider resets the scaling settings for the new provider.\n\nIf --remove is specified, the compute configuration for the Worker\nDeployment Version will be removed:\n\n```\n temporal worker deployment update-version-compute-config \\\n --deployment-name YourDeploymentName --build-id YourBuildID \\\n --remove\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.Command.Flags().StringVar(&s.AwsLambdaFunctionArn, "aws-lambda-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.") @@ -4207,6 +4224,11 @@ func NewTemporalWorkerDeploymentUpdateVersionComputeConfigCommand(cctx *CommandC s.Command.Flags().StringVar(&s.AwsAgentcoreAssumeRoleArn, "aws-agentcore-assume-role-arn", "", "AWS IAM role ARN that the Temporal server will assume when invoking the Agentcore Runtime that spawns a new Worker in this Worker Deployment Version. Required when --aws-agentcore-endpoint-arn is specified, and must be omitted when --aws-agentcore-skip-role-and-external-id is passed.") s.Command.Flags().StringVar(&s.AwsAgentcoreAssumeRoleExternalId, "aws-agentcore-assume-role-external-id", "", "Temporal server will enforce that the AWS IAM trust policy associated with the AWS IAM role specified in --aws-agentcore-assume-role-arn has an aws:ExternalId condition that matches the supplied value. Required when --aws-agentcore-endpoint-arn is specified, and must be omitted when --aws-agentcore-skip-role-and-external-id is passed.") s.Command.Flags().BoolVar(&s.AwsAgentcoreSkipRoleAndExternalId, "aws-agentcore-skip-role-and-external-id", false, "When --aws-agentcore-endpoint-arn is specified, --aws-agentcore-assume-role-arn and --aws-agentcore-assume-role-external-id are required unless this flag is passed, in which case both must be omitted.") + s.Command.Flags().StringVar(&s.ModalAppName, "modal-app-name", "", "Name of the deployed Modal application containing the Worker function. Required when configuring a Modal compute provider.") + s.Command.Flags().StringVar(&s.ModalFunctionName, "modal-function-name", "", "Name of the Modal function to invoke when there are no active pollers for task queue targets in the Worker Deployment. Required when configuring a Modal compute provider.") + s.Command.Flags().StringVar(&s.ModalEnvironment, "modal-environment", "", "Modal environment containing the deployed application. Required when configuring a Modal compute provider.") + s.Command.Flags().StringVar(&s.ModalWorkspaceId, "modal-workspace-id", "", "Optional Modal workspace ID used to select the workspace's credential grant. Omit when the server uses ambient Modal credentials.") + s.Command.Flags().StringVar(&s.ModalVersion, "modal-version", "", "Optional deployed Modal application version, expressed as a non-negative integer. Omit to use the application's current deployed version.") s.Command.Flags().StringVar(&s.GcpCloudRunProject, "gcp-cloud-run-project", "", "GCP project ID hosting the Cloud Run worker pool. Required when --gcp-cloud-run-worker-pool is specified.") s.Command.Flags().StringVar(&s.GcpCloudRunRegion, "gcp-cloud-run-region", "", "Region of the Cloud Run worker pool. Required when --gcp-cloud-run-worker-pool is specified.") s.Command.Flags().StringVar(&s.GcpCloudRunWorkerPool, "gcp-cloud-run-worker-pool", "", "GCP Cloud Run worker pool name to scale when there are no active pollers for task queue targets in the Worker Deployment.") @@ -4292,13 +4314,14 @@ 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 or\nmore scaling groups. Each scaling group is identified by a key, uses a\nsingle compute provider, and may be limited to specific Task Queue\ntypes:\n\n\x1b[1mtemporal worker deployment version compute-config [command] [options]\x1b[0m\n\nCreate a Worker Deployment Version with compute configuration for an\nAWS Lambda function that spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda create \\\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\nRemove a scaling group from the compute configuration of a Version:\n\n\x1b[1mtemporal worker deployment version compute-config remove \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup\x1b[0m\n\nShow the scaling groups in the compute configuration of a Version:\n\n\x1b[1mtemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\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 or\nmore scaling groups. Each scaling group is identified by a key, uses a\nsingle compute provider, and may be limited to specific Task Queue\ntypes and regions:\n\n\x1b[1mtemporal worker deployment version compute-config [command] [options]\x1b[0m\n\nCreate a Worker Deployment Version with compute configuration for an\nAWS Lambda function that spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment version compute-config aws-lambda create \\\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\nCreate a Worker Deployment Version with compute configuration for a\nModal function that spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment version compute-config modal create \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name YourModalApp \\\n --function-name YourModalFunction \\\n --environment YourModalEnvironment\x1b[0m\n\nRemove a scaling group from the compute configuration of a Version:\n\n\x1b[1mtemporal worker deployment version compute-config remove \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup\x1b[0m\n\nShow the scaling groups in the compute configuration of a Version:\n\n\x1b[1mtemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\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 or\nmore scaling groups. Each scaling group is identified by a key, uses a\nsingle compute provider, and may be limited to specific Task Queue\ntypes:\n\n```\ntemporal worker deployment version compute-config [command] [options]\n```\n\nCreate a Worker Deployment Version with compute configuration for an\nAWS Lambda function that spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment version compute-config aws-lambda create \\\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\nRemove a scaling group from the compute configuration of a Version:\n\n```\ntemporal worker deployment version compute-config remove \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup\n```\n\nShow the scaling groups in the compute configuration of a Version:\n\n```\ntemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\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 or\nmore scaling groups. Each scaling group is identified by a key, uses a\nsingle compute provider, and may be limited to specific Task Queue\ntypes and regions:\n\n```\ntemporal worker deployment version compute-config [command] [options]\n```\n\nCreate a Worker Deployment Version with compute configuration for an\nAWS Lambda function that spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment version compute-config aws-lambda create \\\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\nCreate a Worker Deployment Version with compute configuration for a\nModal function that spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment version compute-config modal create \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name YourModalApp \\\n --function-name YourModalFunction \\\n --environment YourModalEnvironment\n```\n\nRemove a scaling group from the compute configuration of a Version:\n\n```\ntemporal worker deployment version compute-config remove \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup\n```\n\nShow the scaling groups in the compute configuration of a Version:\n\n```\ntemporal worker deployment version compute-config describe \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID\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) s.Command.AddCommand(&NewTemporalWorkerDeploymentVersionComputeConfigDescribeCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalWorkerDeploymentVersionComputeConfigModalCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalWorkerDeploymentVersionComputeConfigRemoveCommand(cctx, &s).Command) return &s } @@ -4377,9 +4400,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 settings that are passed change, and\nthe 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 scaling settings of an existing Worker Deployment\nVersion, supply the scaling flags without the provider fields. Scaling\nflags that are not passed go back to the server default:\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 update only the Task Queue types that a scaling group serves, supply\n--task-queue-type without the other fields. The types passed replace\nthe existing ones, and the provider and scaling settings are not\nchanged:\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 --task-queue-type workflow \\\n --task-queue-type activity\x1b[0m\n\nTo make a scaling group serve every Task Queue type again, remove it\nand set it again without --task-queue-type.\n\nProvider fields are only required when changing the compute provider,\nand must be passed together. Changing the provider resets the scaling\nsettings to the scaling flags passed with it.\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 settings that are passed change, and\nthe 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 scaling settings of an existing Worker Deployment\nVersion, supply the scaling flags without the provider fields. Scaling\nflags that are not passed go back to the server default:\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 serves only Workflow Task Queues in one\nregion:\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 --task-queue-type workflow \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\x1b[0m\n\nTo update only the Task Queue types or regions that a scaling group\nserves, supply --task-queue-type or --region-id without the other\nfields. The values passed replace the existing ones, and the provider\nand scaling settings 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 --task-queue-type workflow \\\n --task-queue-type activity\x1b[0m\n\nTo make a scaling group serve every Task Queue type or region again,\nremove it and set it again without --task-queue-type or --region-id.\n\nProvider fields are only required when changing the compute provider,\nand must be passed together. Changing the provider resets the scaling\nsettings to the scaling flags passed with it.\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 settings that are passed change, and\nthe 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 scaling settings of an existing Worker Deployment\nVersion, supply the scaling flags without the provider fields. Scaling\nflags that are not passed go back to the server default:\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 update only the Task Queue types that a scaling group serves, supply\n--task-queue-type without the other fields. The types passed replace\nthe existing ones, and the provider and scaling settings are not\nchanged:\n\n```\ntemporal worker deployment version compute-config aws-lambda update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --scaling-group YourScalingGroup \\\n --task-queue-type workflow \\\n --task-queue-type activity\n```\n\nTo make a scaling group serve every Task Queue type again, remove it\nand set it again without --task-queue-type.\n\nProvider fields are only required when changing the compute provider,\nand must be passed together. Changing the provider resets the scaling\nsettings to the scaling flags passed with it.\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 settings that are passed change, and\nthe 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 scaling settings of an existing Worker Deployment\nVersion, supply the scaling flags without the provider fields. Scaling\nflags that are not passed go back to the server default:\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 serves only Workflow Task Queues in one\nregion:\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 --task-queue-type workflow \\\n --function-arn YourLambdaFunctionARN \\\n --assume-role-arn YourAssumeRoleARN \\\n --assume-role-external-id YourExternalID\n```\n\nTo update only the Task Queue types or regions that a scaling group\nserves, supply --task-queue-type or --region-id without the other\nfields. The values passed replace the existing ones, and the provider\nand scaling settings 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 --task-queue-type workflow \\\n --task-queue-type activity\n```\n\nTo make a scaling group serve every Task Queue type or region again,\nremove it and set it again without --task-queue-type or --region-id.\n\nProvider fields are only required when changing the compute provider,\nand must be passed together. Changing the provider resets the scaling\nsettings to the scaling flags passed with it.\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.") @@ -4408,9 +4431,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 Task Queue types, compute provider, and\nscaler 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 Task Queue types, regions, compute\nprovider, 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." } else { - s.Command.Long = "Show the scaling groups in the compute configuration of a Worker\nDeployment Version, with their Task Queue types, compute provider, and\nscaler 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 Task Queue types, regions, compute\nprovider, 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.Args = cobra.NoArgs s.DeploymentVersionOptions.BuildFlags(s.Command.Flags()) @@ -4422,6 +4445,112 @@ func NewTemporalWorkerDeploymentVersionComputeConfigDescribeCommand(cctx *Comman return &s } +type TemporalWorkerDeploymentVersionComputeConfigModalCommand struct { + Parent *TemporalWorkerDeploymentVersionComputeConfigCommand + Command cobra.Command +} + +func NewTemporalWorkerDeploymentVersionComputeConfigModalCommand(cctx *CommandContext, parent *TemporalWorkerDeploymentVersionComputeConfigCommand) *TemporalWorkerDeploymentVersionComputeConfigModalCommand { + var s TemporalWorkerDeploymentVersionComputeConfigModalCommand + s.Parent = parent + s.Command.Use = "modal" + s.Command.Short = "Create or update Modal compute configuration (Experimental)" + if hasHighlighting { + s.Command.Long = "Modal commands set the compute configuration of a Worker Deployment\nVersion for a Modal function that spawns a Worker in the Worker\nDeployment:\n\n\x1b[1mtemporal worker deployment version compute-config modal [command]\x1b[0m\n\nCreate a Worker Deployment Version with Modal compute configuration:\n\n\x1b[1mtemporal worker deployment version compute-config modal create \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name YourModalApp \\\n --function-name YourModalFunction \\\n --environment YourModalEnvironment\x1b[0m\n\nUpdate the Modal compute configuration of an existing Worker Deployment\nVersion:\n\n\x1b[1mtemporal worker deployment version compute-config modal update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name UpdatedModalApp \\\n --function-name UpdatedModalFunction \\\n --environment UpdatedModalEnvironment\x1b[0m\n\nNote: This is an experimental feature and may change in the future." + } else { + s.Command.Long = "Modal commands set the compute configuration of a Worker Deployment\nVersion for a Modal function that spawns a Worker in the Worker\nDeployment:\n\n```\ntemporal worker deployment version compute-config modal [command]\n```\n\nCreate a Worker Deployment Version with Modal compute configuration:\n\n```\ntemporal worker deployment version compute-config modal create \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name YourModalApp \\\n --function-name YourModalFunction \\\n --environment YourModalEnvironment\n```\n\nUpdate the Modal compute configuration of an existing Worker Deployment\nVersion:\n\n```\ntemporal worker deployment version compute-config modal update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name UpdatedModalApp \\\n --function-name UpdatedModalFunction \\\n --environment UpdatedModalEnvironment\n```\n\nNote: This is an experimental feature and may change in the future." + } + s.Command.Args = cobra.NoArgs + s.Command.AddCommand(&NewTemporalWorkerDeploymentVersionComputeConfigModalCreateCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand(cctx, &s).Command) + return &s +} + +type TemporalWorkerDeploymentVersionComputeConfigModalCreateCommand struct { + Parent *TemporalWorkerDeploymentVersionComputeConfigModalCommand + Command cobra.Command + DeploymentVersionOptions + ScalingGroupOptions + NoSyncScalerOptions + AppName string + FunctionName string + Environment string + WorkspaceId string + Version string +} + +func NewTemporalWorkerDeploymentVersionComputeConfigModalCreateCommand(cctx *CommandContext, parent *TemporalWorkerDeploymentVersionComputeConfigModalCommand) *TemporalWorkerDeploymentVersionComputeConfigModalCreateCommand { + var s TemporalWorkerDeploymentVersionComputeConfigModalCreateCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "create [flags]" + s.Command.Short = "Create a Version with Modal compute configuration (Experimental)" + if hasHighlighting { + s.Command.Long = "Create a new Worker Deployment Version with compute configuration for a\nModal function that spawns a Worker in the Worker Deployment:\n\n\x1b[1mtemporal worker deployment version compute-config modal create \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name YourModalApp \\\n --function-name YourModalFunction \\\n --environment YourModalEnvironment\x1b[0m\n\nTo select a specific Modal workspace or deployed application version,\npass --workspace-id or --version. To tune when Workers are started, pass\nany of the scaling flags. Each scaling flag that is not set keeps the\nserver default.\n\nThe Worker Deployment must already exist; create it with\n\x1b[1mtemporal worker deployment create\x1b[0m.\n\nIf a Worker Deployment Version with the supplied BuildID already exists,\nthis command will return an error. To update its compute configuration,\nuse \x1b[1mtemporal worker deployment version compute-config modal update\x1b[0m.\n\nNote: This is an experimental feature and may change in the future." + } else { + s.Command.Long = "Create a new Worker Deployment Version with compute configuration for a\nModal function that spawns a Worker in the Worker Deployment:\n\n```\ntemporal worker deployment version compute-config modal create \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name YourModalApp \\\n --function-name YourModalFunction \\\n --environment YourModalEnvironment\n```\n\nTo select a specific Modal workspace or deployed application version,\npass --workspace-id or --version. To tune when Workers are started, pass\nany of the scaling flags. Each scaling flag that is not set keeps the\nserver default.\n\nThe Worker Deployment must already exist; create it with\n`temporal worker deployment create`.\n\nIf a Worker Deployment Version with the supplied BuildID already exists,\nthis command will return an error. To update its compute configuration,\nuse `temporal worker deployment version compute-config modal update`.\n\nNote: This is an experimental feature and may change in the future." + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVar(&s.AppName, "app-name", "", "Name of the deployed Modal application containing the Worker function. Required.") + _ = cobra.MarkFlagRequired(s.Command.Flags(), "app-name") + s.Command.Flags().StringVar(&s.FunctionName, "function-name", "", "Name of the Modal function to invoke when there are no active pollers for Task Queue targets in the Worker Deployment. Required.") + _ = cobra.MarkFlagRequired(s.Command.Flags(), "function-name") + s.Command.Flags().StringVar(&s.Environment, "environment", "", "Modal environment containing the deployed application. Required.") + _ = cobra.MarkFlagRequired(s.Command.Flags(), "environment") + s.Command.Flags().StringVar(&s.WorkspaceId, "workspace-id", "", "Optional Modal workspace ID used to select the workspace's credential grant. Omit when the server uses ambient Modal credentials.") + s.Command.Flags().StringVar(&s.Version, "version", "", "Optional deployed Modal application version, expressed as a non-negative integer.") + s.DeploymentVersionOptions.BuildFlags(s.Command.Flags()) + s.ScalingGroupOptions.BuildFlags(s.Command.Flags()) + s.NoSyncScalerOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand struct { + Parent *TemporalWorkerDeploymentVersionComputeConfigModalCommand + Command cobra.Command + DeploymentVersionOptions + ScalingGroupOptions + NoSyncScalerOptions + AppName string + FunctionName string + Environment string + WorkspaceId string + Version string +} + +func NewTemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand(cctx *CommandContext, parent *TemporalWorkerDeploymentVersionComputeConfigModalCommand) *TemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand { + var s TemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "update [flags]" + s.Command.Short = "Update Modal 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 a Modal function that spawns a Worker in the\nWorker Deployment. Only the settings that are passed change, and the\nother scaling groups are not affected.\n\nTo update the Modal application and function associated with an existing\nWorker Deployment Version:\n\n\x1b[1mtemporal worker deployment version compute-config modal update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name UpdatedModalApp \\\n --function-name UpdatedModalFunction \\\n --environment UpdatedModalEnvironment\x1b[0m\n\nTo update only the scaling settings or Task Queue types, pass those flags\nwithout provider fields. Provider fields require --app-name,\n--function-name, and --environment together. Changing the provider resets\nthe scaling settings to the scaling flags passed with it. Optional\n--workspace-id and --version values are omitted from the provider when\nempty.\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 modal 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 a Modal function that spawns a Worker in the\nWorker Deployment. Only the settings that are passed change, and the\nother scaling groups are not affected.\n\nTo update the Modal application and function associated with an existing\nWorker Deployment Version:\n\n```\ntemporal worker deployment version compute-config modal update \\\n --deployment-name YourDeploymentName \\\n --build-id YourBuildID \\\n --app-name UpdatedModalApp \\\n --function-name UpdatedModalFunction \\\n --environment UpdatedModalEnvironment\n```\n\nTo update only the scaling settings or Task Queue types, pass those flags\nwithout provider fields. Provider fields require --app-name,\n--function-name, and --environment together. Changing the provider resets\nthe scaling settings to the scaling flags passed with it. Optional\n--workspace-id and --version values are omitted from the provider when\nempty.\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 modal 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.AppName, "app-name", "", "Name of the deployed Modal application containing the Worker function. Required when changing the compute provider.") + s.Command.Flags().StringVar(&s.FunctionName, "function-name", "", "Name of the Modal function to invoke when there are no active pollers for Task Queue targets in the Worker Deployment. Required when changing the compute provider.") + s.Command.Flags().StringVar(&s.Environment, "environment", "", "Modal environment containing the deployed application. Required when changing the compute provider.") + s.Command.Flags().StringVar(&s.WorkspaceId, "workspace-id", "", "Optional Modal workspace ID used to select the workspace's credential grant. Omit when the server uses ambient Modal credentials.") + s.Command.Flags().StringVar(&s.Version, "version", "", "Optional deployed Modal application version, expressed as a non-negative integer.") + s.DeploymentVersionOptions.BuildFlags(s.Command.Flags()) + s.ScalingGroupOptions.BuildFlags(s.Command.Flags()) + s.NoSyncScalerOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + type TemporalWorkerDeploymentVersionComputeConfigRemoveCommand struct { Parent *TemporalWorkerDeploymentVersionComputeConfigCommand Command cobra.Command diff --git a/internal/temporalcli/commands.worker.deployment.go b/internal/temporalcli/commands.worker.deployment.go index 90b682918..ffc833cef 100644 --- a/internal/temporalcli/commands.worker.deployment.go +++ b/internal/temporalcli/commands.worker.deployment.go @@ -1182,6 +1182,11 @@ type ComputeConfigArgs struct { gcpCloudRunRegion string gcpCloudRunWorkerPool string gcpCloudRunServiceAccount string + modalAppName string + modalFunctionName string + modalEnvironment string + modalWorkspaceID string + modalVersion string } func (c *ComputeConfigArgs) hasAwsLambdaArgs() bool { @@ -1205,24 +1210,34 @@ func (c *ComputeConfigArgs) hasGcpCloudRunArgs() bool { c.gcpCloudRunServiceAccount != "" } +func (c *ComputeConfigArgs) hasModalArgs() bool { + return c.modalAppName != "" || + c.modalFunctionName != "" || + c.modalEnvironment != "" || + c.modalWorkspaceID != "" || + c.modalVersion != "" +} + // computeProviderConfig selects the single compute provider for a Worker // Deployment Version's "default" scaling group from the command's flags. It // enforces that flags for different providers are not mixed, then dispatches on // the trigger flag (--aws-lambda-function-arn / --aws-agentcore-endpoint-arn / -// --gcp-cloud-run-worker-pool). Returns an empty providerType when no provider -// flags are set, leaving the "no configuration" decision to the caller. +// --gcp-cloud-run-worker-pool / --modal-app-name). Returns an empty providerType +// when no provider flags are set, leaving the "no configuration" decision to +// the caller. func computeProviderConfig(c *ComputeConfigArgs) (providerType string, detailsPayload *commonpb.Payload, err error) { awsLambdaSet := c.hasAwsLambdaArgs() awsAgentcoreSet := c.hasAwsAgentcoreArgs() gcpSet := c.hasGcpCloudRunArgs() + modalSet := c.hasModalArgs() setCount := 0 - for _, set := range []bool{awsLambdaSet, awsAgentcoreSet, gcpSet} { + for _, set := range []bool{awsLambdaSet, awsAgentcoreSet, gcpSet, modalSet} { if set { setCount++ } } if setCount > 1 { - return "", nil, fmt.Errorf("cannot combine --aws-lambda-*, --aws-agentcore-*, and --gcp-cloud-run-* flags; a Worker Deployment Version supports a single compute provider") + return "", nil, fmt.Errorf("cannot combine --aws-lambda-*, --aws-agentcore-*, --gcp-cloud-run-*, and --modal-* flags; a Worker Deployment Version supports a single compute provider") } switch { @@ -1250,19 +1265,29 @@ func computeProviderConfig(c *ComputeConfigArgs) (providerType string, detailsPa c.gcpCloudRunServiceAccount, ) return "gcp-cloud-run", p, err + case c.hasModalArgs(): + p, err := modalProviderDetailsPayload( + c.modalAppName, + c.modalFunctionName, + c.modalEnvironment, + c.modalWorkspaceID, + c.modalVersion, + ) + return "modal", p, err default: return "", nil, nil } } // scalerTypeByProvider maps each compute provider to the scaling algorithm -// compatible with its launch strategy in temporal-auto-scaled-workers: aws-lambda -// is invoke-based ("no-sync"); gcp-cloud-run is worker-set-based ("rate-based"). -// WCI rejects an incompatible pairing at CreateWorkerDeploymentVersion. +// compatible with its launch strategy in temporal-auto-scaled-workers. Invoke +// providers use "no-sync"; worker-set providers use "rate-based". WCI rejects +// an incompatible pairing at CreateWorkerDeploymentVersion. var scalerTypeByProvider = map[string]string{ "aws-lambda": "no-sync", "aws-agentcore": "no-sync", "gcp-cloud-run": "rate-based", + "modal": "no-sync", } // scalerTypeForProvider returns the scaling algorithm for the given provider, @@ -1396,6 +1421,11 @@ func (c *TemporalWorkerDeploymentCreateVersionCommand) run(cctx *CommandContext, gcpCloudRunRegion: c.GcpCloudRunRegion, gcpCloudRunWorkerPool: c.GcpCloudRunWorkerPool, gcpCloudRunServiceAccount: c.GcpCloudRunServiceAccount, + modalAppName: c.ModalAppName, + modalFunctionName: c.ModalFunctionName, + modalEnvironment: c.ModalEnvironment, + modalWorkspaceID: c.ModalWorkspaceId, + modalVersion: c.ModalVersion, }) if err != nil { return err @@ -1493,12 +1523,17 @@ func (c *TemporalWorkerDeploymentUpdateVersionComputeConfigCommand) run(cctx *Co gcpCloudRunRegion: c.GcpCloudRunRegion, gcpCloudRunWorkerPool: c.GcpCloudRunWorkerPool, gcpCloudRunServiceAccount: c.GcpCloudRunServiceAccount, + modalAppName: c.ModalAppName, + modalFunctionName: c.ModalFunctionName, + modalEnvironment: c.ModalEnvironment, + modalWorkspaceID: c.ModalWorkspaceId, + modalVersion: c.ModalVersion, } if c.Remove { - if computeConfigArgs.hasAwsLambdaArgs() || computeConfigArgs.hasAwsAgentcoreArgs() || computeConfigArgs.hasGcpCloudRunArgs() || + if computeConfigArgs.hasAwsLambdaArgs() || computeConfigArgs.hasAwsAgentcoreArgs() || computeConfigArgs.hasGcpCloudRunArgs() || computeConfigArgs.hasModalArgs() || c.gcpScalerFlags().anySet() { - return fmt.Errorf("--remove cannot be combined with --aws-lambda-*, --aws-agentcore-*, or --gcp-cloud-run-* flags") + return fmt.Errorf("--remove cannot be combined with --aws-lambda-*, --aws-agentcore-*, --gcp-cloud-run-*, or --modal-* flags") } request.RemoveComputeConfigScalingGroups = []string{"default"} } else { diff --git a/internal/temporalcli/commands.worker.deployment.internal_test.go b/internal/temporalcli/commands.worker.deployment.internal_test.go index 3498071eb..4388da714 100644 --- a/internal/temporalcli/commands.worker.deployment.internal_test.go +++ b/internal/temporalcli/commands.worker.deployment.internal_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "github.com/temporalio/cli/internal/printer" + commonpb "go.temporal.io/api/common/v1" computepb "go.temporal.io/api/compute/v1" deploymentpb "go.temporal.io/api/deployment/v1" enumspb "go.temporal.io/api/enums/v1" @@ -24,6 +25,7 @@ func TestScalerTypeForProvider(t *testing.T) { }{ {"aws-lambda is invoke-based -> no-sync", "aws-lambda", "no-sync", false}, {"aws-agentcore is invoke-based -> no-sync", "aws-agentcore", "no-sync", false}, + {"modal is invoke-based -> no-sync", "modal", "no-sync", false}, {"gcp-cloud-run is worker-set-based -> rate-based", "gcp-cloud-run", "rate-based", false}, {"unknown provider errors", "azure-container-apps", "", true}, {"empty provider errors", "", "", true}, @@ -45,12 +47,67 @@ func TestScalerTypeForProvider(t *testing.T) { // scaler mapping; a missing entry makes scalerTypeForProvider error before the // request is sent, so this guards against forgetting to map a newly-added provider. func TestScalerTypeByProviderCoversAllProviders(t *testing.T) { - for _, providerType := range []string{"aws-lambda", "aws-agentcore", "gcp-cloud-run"} { + for _, providerType := range []string{"aws-lambda", "aws-agentcore", "gcp-cloud-run", "modal"} { _, ok := scalerTypeByProvider[providerType] require.Truef(t, ok, "provider %q has no scaler mapping", providerType) } } +func TestModalProviderDetailsPayload(t *testing.T) { + decode := func(t *testing.T, payload *commonpb.Payload) map[string]any { + t.Helper() + var details map[string]any + require.NoError(t, converter.GetDefaultDataConverter().FromPayload(payload, &details)) + return details + } + + p, err := modalProviderDetailsPayload("payments", "worker", "main", "", "") + require.NoError(t, err) + details := decode(t, p) + require.Equal(t, "payments", details["app_name"]) + require.Equal(t, "worker", details["function_name"]) + require.Equal(t, "main", details["environment"]) + require.NotContains(t, details, "workspace_id") + require.NotContains(t, details, "version") + + p, err = modalProviderDetailsPayload("payments", "worker", "staging", "ws-123", "42") + require.NoError(t, err) + details = decode(t, p) + require.Equal(t, "staging", details["environment"]) + require.Equal(t, "ws-123", details["workspace_id"]) + require.Equal(t, "42", details["version"]) + + _, err = modalProviderDetailsPayload("", "worker", "main", "", "") + require.ErrorContains(t, err, "missing required Modal provider detail: app_name") + _, err = modalProviderDetailsPayload("payments", "", "main", "", "") + require.ErrorContains(t, err, "missing required Modal provider detail: function_name") + _, err = modalProviderDetailsPayload("payments", "worker", "", "", "") + require.ErrorContains(t, err, "missing required Modal provider detail: environment") + _, err = modalProviderDetailsPayload("payments", "worker", "main", "", "-1") + require.ErrorContains(t, err, "must be a non-negative integer string") + _, err = modalProviderDetailsPayload("payments", "worker", "main", "", "latest") + require.ErrorContains(t, err, "must be a non-negative integer string") +} + +func TestComputeProviderConfig_Modal(t *testing.T) { + providerType, payload, err := computeProviderConfig(&ComputeConfigArgs{ + modalAppName: "payments", + modalFunctionName: "worker", + modalEnvironment: "main", + }) + require.NoError(t, err) + require.Equal(t, "modal", providerType) + require.NotNil(t, payload) + + _, _, err = computeProviderConfig(&ComputeConfigArgs{ + awsLambdaFunctionArn: "arn:aws:lambda:us-east-1:123:function:worker", + modalAppName: "payments", + modalFunctionName: "worker", + modalEnvironment: "main", + }) + require.ErrorContains(t, err, "cannot combine") +} + func TestGCPCloudRunScalerDetails(t *testing.T) { // A fully-set, valid group; each case clones this and overrides one field so // the all-or-none check passes and the case isolates a single value check. 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 06fe4e100..875b07021 100644 --- a/internal/temporalcli/commands.worker.deployment.version.aws_lambda_test.go +++ b/internal/temporalcli/commands.worker.deployment.version.aws_lambda_test.go @@ -166,7 +166,7 @@ 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_TaskQueueTypes() { +func (s *SharedServerSuite) TestComputeConfig_AwsLambda_TaskQueueTypesAndRegions() { fake := s.newFakeComputeConfigServer() fake.setComputeConfig(nil) @@ -174,6 +174,7 @@ func (s *SharedServerSuite) TestComputeConfig_AwsLambda_TaskQueueTypes() { "--scaling-group", "use1", "--task-queue-type", "nexus", "--task-queue-type", "workflow", + "--region-id", "aws-us-east-1", )...) s.NoError(res.Err) s.Empty(res.Stderr.String()) @@ -181,6 +182,39 @@ func (s *SharedServerSuite) TestComputeConfig_AwsLambda_TaskQueueTypes() { s.Len(updates, 1) sg := updates[0].GetComputeConfigScalingGroups()["use1"].GetScalingGroup() s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_WORKFLOW, enumspb.TASK_QUEUE_TYPE_NEXUS}, sg.GetTaskQueueTypes()) + s.Equal([]string{"aws-us-east-1"}, sg.GetRegionIds()) +} + +func (s *SharedServerSuite) TestComputeConfig_AwsLambda_RegionIDs() { + fake := s.newFakeComputeConfigServer() + fake.setComputeConfig(nil) + deploymentName := uuid.NewString() + regionArgs := lambdaComputeConfigArgs("update", s.Address(), deploymentName, + "--scaling-group", "aws-us-west-2", + "--region-id", "aws-us-west-2", + "--region-id", "aws-us-east-1", + "--region-id", "aws-us-west-2", + ) + + // Region IDs are de-duplicated and sorted, and the mask covers them. + res := s.Execute(regionArgs...) + s.NoError(res.Err) + s.Empty(res.Stderr.String()) + updates := fake.takeUpdates() + s.Len(updates, 1) + update := updates[0].GetComputeConfigScalingGroups()["aws-us-west-2"] + s.Equal([]string{"aws-us-east-1", "aws-us-west-2"}, 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 IDs. + res = s.Execute(lambdaComputeConfigArgs("update", s.Address(), deploymentName, "--scaling-group", "aws-us-west-2")...) + s.NoError(res.Err) + updates = fake.takeUpdates() + s.Len(updates, 1) + update = updates[0].GetComputeConfigScalingGroups()["aws-us-west-2"] + s.Empty(update.GetScalingGroup().GetRegionIds()) + s.NotContains(update.GetUpdateMask().GetPaths(), "region_ids") + s.Equal([]string{"aws-us-east-1", "aws-us-west-2"}, fake.computeConfig.GetScalingGroups()["aws-us-west-2"].GetRegionIds()) } func (s *SharedServerSuite) TestComputeConfig_AwsLambda_ScalerSettings() { @@ -263,6 +297,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 IDs. + res = s.Execute(args("--scaling-group", "aws-us-east-1-wf", "--region-id", "aws-us-west-2", "--region-id", "aws-us-east-1")...) + 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-east-1", "aws-us-west-2"}, sg.GetRegionIds()) + s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_WORKFLOW}, sg.GetTaskQueueTypes()) + s.Equal("aws-lambda", sg.GetProvider().GetType()) // --task-queue-type on its own changes only the Task Queue types. res = s.Execute(args("--scaling-group", "aws-us-east-1-wf", "--task-queue-type", "nexus")...) @@ -270,6 +314,7 @@ func (s *SharedServerSuite) TestComputeConfig_AwsLambda_PartialUpdate() { s.Equal([]string{"task_queue_types"}, onlyUpdate("aws-us-east-1-wf").GetUpdateMask().GetPaths()) sg = stored("aws-us-east-1-wf") s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_NEXUS}, sg.GetTaskQueueTypes()) + s.Equal([]string{"aws-us-east-1", "aws-us-west-2"}, sg.GetRegionIds()) s.Equal("aws-lambda", sg.GetProvider().GetType()) s.Equal("no-sync", sg.GetScaler().GetType()) @@ -285,6 +330,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 { @@ -365,6 +411,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 a22e87a22..e7189a1b3 100644 --- a/internal/temporalcli/commands.worker.deployment.version.go +++ b/internal/temporalcli/commands.worker.deployment.version.go @@ -113,6 +113,7 @@ func (c *TemporalWorkerDeploymentVersionComputeConfigDescribeCommand) run(cctx * type scalingGroupCard struct { ScalingGroup string TaskQueueTypes string `cli:",cardOmitEmpty"` + RegionIds string `cli:",cardOmitEmpty"` Provider string `cli:",cardOmitEmpty"` Scaler string `cli:",cardOmitEmpty"` } @@ -123,6 +124,7 @@ func (c *TemporalWorkerDeploymentVersionComputeConfigDescribeCommand) run(cctx * card := scalingGroupCard{ ScalingGroup: key, TaskQueueTypes: strings.Join(sg.TaskQueueTypes, ", "), + RegionIds: strings.Join(sg.RegionIds, ", "), } if sg.Provider != nil { card.Provider = sg.Provider.Type @@ -217,7 +219,7 @@ func (c *TemporalWorkerDeploymentVersionComputeConfigRemoveCommand) run(cctx *Co } // scalingGroup builds the provider-independent part of a scaling group from -// the --scaling-group and --task-queue-type flags. +// the --scaling-group, --task-queue-type, and --region-id flags. func (o *ScalingGroupOptions) scalingGroup() (*computepb.ComputeConfigScalingGroup, error) { if o.ScalingGroup == "" { return nil, fmt.Errorf("--scaling-group cannot be empty") @@ -240,6 +242,15 @@ func (o *ScalingGroupOptions) scalingGroup() (*computepb.ComputeConfigScalingGro } } slices.Sort(sg.TaskQueueTypes) + for _, r := range o.RegionId { + if r == "" { + return nil, fmt.Errorf("--region-id cannot be empty") + } + if !slices.Contains(sg.RegionIds, r) { + sg.RegionIds = append(sg.RegionIds, r) + } + } + slices.Sort(sg.RegionIds) return sg, nil } @@ -256,6 +267,11 @@ func (o *ScalingGroupOptions) update() (*computepb.ComputeConfigScalingGroup, [] } else { sg.TaskQueueTypes = nil } + if o.FlagSet.Changed("region-id") { + paths = append(paths, "region_ids") + } else { + sg.RegionIds = nil + } return sg, paths, nil } @@ -443,6 +459,7 @@ type formattedComputeConfigDescription struct { type formattedScalingGroupDescription struct { TaskQueueTypes []string `json:"taskQueueTypes,omitempty"` + RegionIds []string `json:"regionIds,omitempty"` Provider *formattedComputeConfigProvider `json:"provider,omitempty"` Scaler *formattedScalerDescription `json:"scaler,omitempty"` } @@ -462,7 +479,7 @@ type formattedScalerDescription struct { func formatComputeConfigDescription(cc *computepb.ComputeConfig) formattedComputeConfigDescription { out := formattedComputeConfigDescription{ScalingGroups: map[string]formattedScalingGroupDescription{}} for name, msgSG := range cc.GetScalingGroups() { - var sg formattedScalingGroupDescription + sg := formattedScalingGroupDescription{RegionIds: msgSG.GetRegionIds()} for _, t := range msgSG.GetTaskQueueTypes() { str, err := taskQueueTypeProtoToStr(t) if err != nil { diff --git a/internal/temporalcli/commands.worker.deployment.version.modal.go b/internal/temporalcli/commands.worker.deployment.version.modal.go new file mode 100644 index 000000000..1a4c2e3c5 --- /dev/null +++ b/internal/temporalcli/commands.worker.deployment.version.modal.go @@ -0,0 +1,118 @@ +package temporalcli + +import ( + "fmt" + "slices" + "strconv" + + commonpb "go.temporal.io/api/common/v1" + computepb "go.temporal.io/api/compute/v1" + "go.temporal.io/sdk/converter" +) + +func (c *TemporalWorkerDeploymentVersionComputeConfigModalCreateCommand) run(cctx *CommandContext, args []string) error { + provider, err := modalProvider(c.AppName, c.FunctionName, c.Environment, c.WorkspaceId, c.Version) + if err != nil { + return err + } + scalerDetails, err := c.NoSyncScalerOptions.details() + if err != nil { + return err + } + sg, err := noSyncScalingGroup(&c.ScalingGroupOptions, provider, scalerDetails) + if err != nil { + return err + } + return createVersionWithScalingGroup(cctx, c.Parent.Parent.Parent.Parent.Parent, c.deploymentVersion(), c.ScalingGroup, sg, "modal") +} + +func (c *TemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand) run(cctx *CommandContext, args []string) error { + provider, err := c.provider() + if err != nil { + return err + } + scalerDetails, err := c.NoSyncScalerOptions.details() + if err != nil { + return err + } + update, err := noSyncScalingGroupUpdate(&c.ScalingGroupOptions, provider, scalerDetails) + if err != nil { + return err + } + return updateVersionScalingGroup(cctx, c.Parent.Parent.Parent.Parent.Parent, c.deploymentVersion(), c.ScalingGroup, update, "modal") +} + +// provider returns the Modal provider to set, or nil to leave it unchanged. +// The required provider flags are passed together because provider details are +// replaced as a whole; workspace and version remain optional. +func (c *TemporalWorkerDeploymentVersionComputeConfigModalUpdateCommand) provider() (*computepb.ComputeProvider, error) { + flags := c.Command.Flags() + providerSet := slices.ContainsFunc( + []string{"app-name", "function-name", "environment", "workspace-id", "version"}, + flags.Changed, + ) + if !providerSet { + return nil, nil + } + if !flags.Changed("app-name") || !flags.Changed("function-name") || !flags.Changed("environment") { + return nil, fmt.Errorf("--app-name, --function-name, and --environment are required when changing the provider") + } + return modalProvider(c.AppName, c.FunctionName, c.Environment, c.WorkspaceId, c.Version) +} + +// The Modal compute provider. +const modalProviderType = "modal" + +// modalProvider builds the Modal compute provider from the provider flags. +func modalProvider(appName, functionName, environment, workspaceID, version string) (*computepb.ComputeProvider, error) { + payload, err := modalProviderDetailsPayload(appName, functionName, environment, workspaceID, version) + if err != nil { + return nil, err + } + return &computepb.ComputeProvider{Type: modalProviderType, Details: payload}, nil +} + +func validateModalProviderDetails(details map[string]any) error { + for _, key := range []string{"app_name", "function_name", "environment"} { + if v, ok := details[key].(string); !ok || v == "" { + return fmt.Errorf("missing required Modal provider detail: %s", key) + } + } + if rawVersion, ok := details["version"]; ok { + version, ok := rawVersion.(string) + parsed, err := strconv.Atoi(version) + if !ok || err != nil || parsed < 0 { + return fmt.Errorf("Modal provider detail %q must be a non-negative integer string", "version") + } + } + return nil +} + +// modalProviderDetailsPayload returns the encoded Payload expected by WCI's +// invoke-based Modal provider. The environment is part of the compute resource +// identity and must be explicit so provider updates cannot silently change it. +func modalProviderDetailsPayload( + appName string, + functionName string, + environment string, + workspaceID string, + version string, +) (*commonpb.Payload, error) { + // Map keys from temporal-auto-scaled-workers: + // https://github.com/temporalio/temporal-auto-scaled-workers/blob/324950cf843e560ff0c6531070bb1d4e139d5000/wci/workflow/compute_provider/modal.go#L18-L24 + providerDetails := map[string]any{ + "app_name": appName, + "function_name": functionName, + "environment": environment, + } + if workspaceID != "" { + providerDetails["workspace_id"] = workspaceID + } + if version != "" { + providerDetails["version"] = version + } + if err := validateModalProviderDetails(providerDetails); err != nil { + return nil, err + } + return converter.GetDefaultDataConverter().ToPayload(&providerDetails) +} diff --git a/internal/temporalcli/commands.worker.deployment.version.modal_test.go b/internal/temporalcli/commands.worker.deployment.version.modal_test.go new file mode 100644 index 000000000..02ae13d9f --- /dev/null +++ b/internal/temporalcli/commands.worker.deployment.version.modal_test.go @@ -0,0 +1,152 @@ +package temporalcli_test + +import ( + "github.com/google/uuid" + enumspb "go.temporal.io/api/enums/v1" +) + +func modalComputeConfigArgs(verb, address, deploymentName string, extra ...string) []string { + return append([]string{ + "worker", "deployment", "version", "compute-config", "modal", verb, + "--address", address, + "--deployment-name", deploymentName, + "--build-id", "build-17", + "--app-name", "payments", + "--function-name", "worker", + "--environment", "main", + }, extra...) +} + +func (s *SharedServerSuite) TestComputeConfig_Modal_Create() { + fake := s.newFakeComputeConfigServer() + fake.versionMissing = true + deploymentName := uuid.NewString() + + res := s.Execute(modalComputeConfigArgs("create", s.Address(), deploymentName, + "--workspace-id", "ws-123", + "--version", "7", + "--region-id", "modal-us", + )...) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "Successfully created worker deployment version") + s.Empty(fake.takeUpdates()) + creates := fake.takeCreates() + s.Len(creates, 1) + s.Equal(deploymentName, creates[0].GetDeploymentVersion().GetDeploymentName()) + s.Equal("build-17", creates[0].GetDeploymentVersion().GetBuildId()) + s.NotEmpty(creates[0].GetRequestId()) + sg := creates[0].GetComputeConfig().GetScalingGroups()["default"] + s.NotNil(sg) + s.Equal([]string{"modal-us"}, sg.GetRegionIds()) + s.Equal("modal", sg.GetProvider().GetType()) + s.Equal(map[string]any{ + "app_name": "payments", + "function_name": "worker", + "environment": "main", + "workspace_id": "ws-123", + "version": "7", + }, s.decodePayloadMap(sg.GetProvider().GetDetails())) + s.Equal("no-sync", sg.GetScaler().GetType()) + s.Nil(sg.GetScaler().GetDetails()) + + res = s.Execute(modalComputeConfigArgs("create", s.Address(), deploymentName)...) + s.ErrorContains(res.Err, "error creating worker deployment version: Worker Deployment Version already exists; "+ + "to set its compute config, use `temporal worker deployment version compute-config modal update`") + s.Len(fake.takeCreates(), 1) +} + +func (s *SharedServerSuite) TestComputeConfig_Modal_Update() { + fake := s.newFakeComputeConfigServer() + fake.setComputeConfig(nil) + deploymentName := uuid.NewString() + + res := s.Execute(modalComputeConfigArgs("update", s.Address(), deploymentName, + "--scaling-group", "modal-workflows", + "--task-queue-type", "workflow", + "--region-id", "modal-us", + "--scale-up-backlog-threshold", "5", + )...) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "Successfully updated worker deployment version compute config") + s.Empty(fake.takeCreates()) + updates := fake.takeUpdates() + s.Len(updates, 1) + update := updates[0].GetComputeConfigScalingGroups()["modal-workflows"] + s.NotNil(update) + s.Equal([]string{"task_queue_types", "region_ids", "provider.type", "provider.details", "scaler.type", "scaler.details"}, update.GetUpdateMask().GetPaths()) + sg := update.GetScalingGroup() + s.Equal([]enumspb.TaskQueueType{enumspb.TASK_QUEUE_TYPE_WORKFLOW}, sg.GetTaskQueueTypes()) + s.Equal([]string{"modal-us"}, sg.GetRegionIds()) + s.Equal("modal", sg.GetProvider().GetType()) + s.Equal(map[string]any{ + "app_name": "payments", + "function_name": "worker", + "environment": "main", + }, s.decodePayloadMap(sg.GetProvider().GetDetails())) + s.Equal("no-sync", sg.GetScaler().GetType()) + s.Equal(map[string]any{"scale_up_backlog_threshold": float64(5)}, s.decodePayloadMap(sg.GetScaler().GetDetails())) + + // Scaling settings can be changed without resending the provider fields. + res = s.Execute( + "worker", "deployment", "version", "compute-config", "modal", "update", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", "build-17", + "--scaling-group", "modal-workflows", + "--max-worker-lifetime-ms", "300000", + ) + s.NoError(res.Err) + updates = fake.takeUpdates() + s.Len(updates, 1) + update = updates[0].GetComputeConfigScalingGroups()["modal-workflows"] + s.Equal([]string{"scaler.details"}, update.GetUpdateMask().GetPaths()) + s.Nil(update.GetScalingGroup().GetProvider()) + s.Equal(map[string]any{"max_worker_lifetime_ms": float64(300000)}, + s.decodePayloadMap(update.GetScalingGroup().GetScaler().GetDetails())) + s.Equal([]string{"modal-us"}, fake.computeConfig.GetScalingGroups()["modal-workflows"].GetRegionIds()) +} + +func (s *SharedServerSuite) TestComputeConfig_Modal_Errors() { + fake := s.newFakeComputeConfigServer() + fake.setComputeConfig(nil) + deploymentName := uuid.NewString() + base := []string{ + "worker", "deployment", "version", "compute-config", "modal", "update", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", "build-17", + } + + for _, tc := range []struct { + name string + args []string + errText string + }{ + { + name: "provider fields must be passed together", + args: append(append([]string{}, base...), "--app-name", "payments"), + errText: "--app-name, --function-name, and --environment are required when changing the provider", + }, + { + name: "environment cannot be empty", + args: append(append([]string{}, base...), + "--app-name", "payments", "--function-name", "worker", "--environment", ""), + errText: "missing required Modal provider detail: environment", + }, + { + name: "version must be non-negative", + args: append(append([]string{}, base...), + "--app-name", "payments", "--function-name", "worker", "--environment", "main", "--version", "-1"), + errText: `Modal provider detail "version" must be a non-negative integer string`, + }, + { + name: "nothing to update", + args: append([]string{}, base...), + errText: "no compute configuration provided to update", + }, + } { + res := s.Execute(tc.args...) + s.ErrorContains(res.Err, tc.errText, tc.name) + } + s.Empty(fake.takeUpdates()) +} diff --git a/internal/temporalcli/commands.worker.deployment.version_test.go b/internal/temporalcli/commands.worker.deployment.version_test.go index 28f4711bb..db5892faf 100644 --- a/internal/temporalcli/commands.worker.deployment.version_test.go +++ b/internal/temporalcli/commands.worker.deployment.version_test.go @@ -97,6 +97,8 @@ func (f *fakeComputeConfigServer) update(key string, update *computepb.ComputeCo switch path { case "task_queue_types": merged.TaskQueueTypes = src.GetTaskQueueTypes() + case "region_ids": + merged.RegionIds = src.GetRegionIds() case "provider.type", "provider.details": if merged.Provider == nil { merged.Provider = &computepb.ComputeProvider{} @@ -214,11 +216,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"}, }, @@ -255,11 +259,13 @@ func (s *SharedServerSuite) TestComputeConfig_Describe() { s.Len(cards, 2) s.ContainsOnSameLine(cards[0], "ScalingGroup", "aws-us-east-1-wf") s.ContainsOnSameLine(cards[0], "TaskQueueTypes", "workflow") + s.ContainsOnSameLine(cards[0], "RegionIds", "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], "TaskQueueTypes", "activity") + s.ContainsOnSameLine(cards[1], "RegionIds", "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)") @@ -268,6 +274,7 @@ func (s *SharedServerSuite) TestComputeConfig_Describe() { var described struct { ScalingGroups map[string]struct { TaskQueueTypes []string `json:"taskQueueTypes"` + RegionIds []string `json:"regionIds"` Provider struct { Type string `json:"type"` } `json:"provider"` @@ -284,10 +291,12 @@ func (s *SharedServerSuite) TestComputeConfig_Describe() { s.Len(described.ScalingGroups, 2) wf := described.ScalingGroups["aws-us-east-1-wf"] s.Equal([]string{"workflow"}, wf.TaskQueueTypes) + s.Equal([]string{"aws-us-east-1"}, wf.RegionIds) s.Equal("aws-lambda", wf.Provider.Type) s.Equal("no-sync", wf.Scaler.Type) ac := described.ScalingGroups["aws-us-west-2-ac"] s.Equal([]string{"activity"}, ac.TaskQueueTypes) + s.Equal([]string{"aws-us-west-2"}, ac.RegionIds) 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. diff --git a/internal/temporalcli/commands.worker.deployment_test.go b/internal/temporalcli/commands.worker.deployment_test.go index 7b9232da2..880b66b32 100644 --- a/internal/temporalcli/commands.worker.deployment_test.go +++ b/internal/temporalcli/commands.worker.deployment_test.go @@ -1530,7 +1530,7 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { "--gcp-cloud-run-worker-pool", "my-worker-pool", ) s.Error(res.Err) - s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, and --gcp-cloud-run-* flags") + s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, --gcp-cloud-run-*, and --modal-* flags") // AWS Agentcore and Lambda providers are mutually exclusive on create. res = s.Execute( @@ -1543,7 +1543,7 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { "--aws-lambda-assume-role-external-id", assumeRoleExternalID, ) s.Error(res.Err) - s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, and --gcp-cloud-run-* flags") + s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, --gcp-cloud-run-*, and --modal-* flags") // --gcp-cloud-run-worker-pool requires project, region, and // service-account; the first missing detail key is reported. @@ -1574,6 +1574,51 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { s.Error(res.Err) s.ErrorContains(res.Err, "missing required GCP Cloud Run provider detail: service_account") + // Modal requires the deployed App, Function, and environment. + res = s.Execute( + "worker", "deployment", "create-version", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", uuid.NewString(), + "--modal-app-name", "payments", + ) + s.Error(res.Err) + s.ErrorContains(res.Err, "missing required Modal provider detail: function_name") + + res = s.Execute( + "worker", "deployment", "create-version", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", uuid.NewString(), + "--modal-function-name", "worker", + ) + s.Error(res.Err) + s.ErrorContains(res.Err, "missing required Modal provider detail: app_name") + + res = s.Execute( + "worker", "deployment", "create-version", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", uuid.NewString(), + "--modal-app-name", "payments", + "--modal-function-name", "worker", + ) + s.Error(res.Err) + s.ErrorContains(res.Err, "missing required Modal provider detail: environment") + + res = s.Execute( + "worker", "deployment", "create-version", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", uuid.NewString(), + "--modal-app-name", "payments", + "--modal-function-name", "worker", + "--modal-environment", "main", + "--modal-version", "-1", + ) + s.Error(res.Err) + s.ErrorContains(res.Err, "Modal provider detail \"version\" must be a non-negative integer string") + // AWS Lambda and GCP Cloud Run providers are mutually exclusive on create. mixedProvidersBuildID := uuid.NewString() @@ -1586,7 +1631,7 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { "--gcp-cloud-run-worker-pool", "my-worker-pool", ) s.Error(res.Err) - s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, and --gcp-cloud-run-* flags") + s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, --gcp-cloud-run-*, and --modal-* flags") // Attempting to update the compute config for a non-existent WDV // should fail. @@ -1626,7 +1671,7 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { "--gcp-cloud-run-worker-pool", "my-worker-pool", ) s.Error(res.Err) - s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, and --gcp-cloud-run-* flags") + s.ErrorContains(res.Err, "cannot combine --aws-lambda-*, --aws-agentcore-*, --gcp-cloud-run-*, and --modal-* flags") // --remove cannot be combined with GCP Cloud Run flags. res = s.Execute( @@ -1640,6 +1685,18 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { s.Error(res.Err) s.ErrorContains(res.Err, "--remove cannot be combined with") + // --remove cannot be combined with Modal provider flags either. + res = s.Execute( + "worker", "deployment", "update-version-compute-config", + "--address", s.Address(), + "--deployment-name", deploymentName, + "--build-id", lazyCreatedBuildID, + "--modal-app-name", "payments", + "--remove", + ) + s.Error(res.Err) + s.ErrorContains(res.Err, "--remove cannot be combined with") + // --remove cannot be combined with the scaler settings flags either; a lone // scaler flag alongside --remove is contradictory and rejected client-side. res = s.Execute( @@ -1886,6 +1943,56 @@ func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_Errors() { s.ErrorContains(res.Err, "only valid with --gcp-cloud-run-worker-pool") } +func (s *SharedServerSuite) TestCreateWorkerDeploymentVersion_ModalRequest() { + var mu sync.Mutex + var captured *workflowservice.CreateWorkerDeploymentVersionRequest + s.CommandHarness.Options.AdditionalClientGRPCDialOptions = append( + s.CommandHarness.Options.AdditionalClientGRPCDialOptions, + grpc.WithChainUnaryInterceptor(func( + ctx context.Context, method string, req, reply any, + cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption, + ) error { + if r, ok := req.(*workflowservice.CreateWorkerDeploymentVersionRequest); ok { + mu.Lock() + captured = r + mu.Unlock() + return nil // capture only; do not forward to the server + } + return invoker(ctx, method, req, reply, cc, opts...) + }), + ) + takeCaptured := func() *workflowservice.CreateWorkerDeploymentVersionRequest { + mu.Lock() + defer mu.Unlock() + r := captured + captured = nil + return r + } + + res := s.Execute( + "worker", "deployment", "create-version", + "--address", s.Address(), + "--deployment-name", uuid.NewString(), "--build-id", "1.0", + "--modal-app-name", "payments", + "--modal-function-name", "worker", + "--modal-environment", "main", + ) + s.NoError(res.Err) + createReq := takeCaptured() + s.NotNil(createReq) + createGroup := createReq.GetComputeConfig().GetScalingGroups()["default"] + s.Equal("modal", createGroup.GetProvider().GetType()) + s.Equal("no-sync", createGroup.GetScaler().GetType()) + s.Nil(createGroup.GetScaler().GetDetails()) + var modalDetails map[string]any + s.NoError(converter.GetDefaultDataConverter().FromPayload(createGroup.GetProvider().GetDetails(), &modalDetails)) + s.Equal("payments", modalDetails["app_name"]) + s.Equal("worker", modalDetails["function_name"]) + s.Equal("main", modalDetails["environment"]) + s.NotContains(modalDetails, "workspace_id") + s.NotContains(modalDetails, "version") +} + // TestUpdateWorkerDeploymentVersionComputeConfig_UpdateModes verifies the shape // of the update request for each mode. It captures the outbound gRPC request and // short-circuits it, so the assertions don't need a real (GCP-backed) version on @@ -1965,6 +2072,32 @@ func (s *SharedServerSuite) TestUpdateWorkerDeploymentVersionComputeConfig_Updat s.Equal("aws-lambda", sg.GetScalingGroup().GetProvider().GetType()) s.Nil(sg.GetScalingGroup().GetScaler().GetDetails()) + // Switching to Modal also clears rate-based scaler details and includes the + // required environment plus optional workspace and App version. + res = s.Execute( + "worker", "deployment", "update-version-compute-config", + "--address", s.Address(), + "--deployment-name", deploymentName, "--build-id", buildID, + "--modal-app-name", "payments", + "--modal-function-name", "worker", + "--modal-environment", "staging", + "--modal-workspace-id", "ws-123", + "--modal-version", "42", + ) + s.NoError(res.Err) + req = takeCaptured() + s.NotNil(req) + sg = req.GetComputeConfigScalingGroups()["default"] + s.Contains(sg.GetUpdateMask().GetPaths(), "scaler.details") + s.Equal("modal", sg.GetScalingGroup().GetProvider().GetType()) + s.Equal("no-sync", sg.GetScalingGroup().GetScaler().GetType()) + s.Nil(sg.GetScalingGroup().GetScaler().GetDetails()) + var modalDetails map[string]any + s.NoError(converter.GetDefaultDataConverter().FromPayload(sg.GetScalingGroup().GetProvider().GetDetails(), &modalDetails)) + s.Equal("staging", modalDetails["environment"]) + s.Equal("ws-123", modalDetails["workspace_id"]) + s.Equal("42", modalDetails["version"]) + // Updating only GCP provider fields (no scaler flags) leaves scaler.details // out of the mask, so existing bounds are preserved. res = s.Execute( diff --git a/internal/temporalcli/commands.yaml b/internal/temporalcli/commands.yaml index c3e76fdf7..2b8d6d34d 100644 --- a/internal/temporalcli/commands.yaml +++ b/internal/temporalcli/commands.yaml @@ -1269,6 +1269,19 @@ commands: --aws-agentcore-assume-role-external-id AgentcoreAssumeRoleExternalID ``` + Or pass a deployed Modal application and function that spawns a Worker in + the Worker Deployment: + + ``` + temporal worker deployment create-version \ + --namespace YourNamespaceName \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --modal-app-name YourModalApp \ + --modal-function-name YourModalFunction \ + --modal-environment main + ``` + Or pass compute provider information for a GCP Cloud Run worker pool that spawns a Worker in the Worker Deployment: @@ -1354,6 +1367,33 @@ commands: When --aws-agentcore-endpoint-arn is specified, --aws-agentcore-assume-role-arn and --aws-agentcore-assume-role-external-id are required unless this flag is passed, in which case both must be omitted. + - name: modal-app-name + type: string + description: | + Name of the deployed Modal application containing the Worker + function. Required when configuring a Modal compute provider. + - name: modal-function-name + type: string + description: | + Name of the Modal function to invoke when there are no active pollers + for task queue targets in the Worker Deployment. Required when + configuring a Modal compute provider. + - name: modal-environment + type: string + description: | + Modal environment containing the deployed application. Required when + configuring a Modal compute provider. + - name: modal-workspace-id + type: string + description: | + Optional Modal workspace ID used to select the workspace's credential + grant. Omit when the server uses ambient Modal credentials. + - name: modal-version + type: string + description: | + Optional deployed Modal application version, expressed as a + non-negative integer. Omit to use the application's current deployed + version. - name: gcp-cloud-run-project type: string description: | @@ -1664,6 +1704,17 @@ commands: --aws-agentcore-assume-role-external-id UpdatedExternalID ``` + To update the Modal application and function associated with an existing + Worker Deployment Version: + + ``` + temporal worker deployment update-version-compute-config \ + --deployment-name YourDeploymentName --build-id YourBuildID \ + --modal-app-name UpdatedModalApp \ + --modal-function-name UpdatedModalFunction \ + --modal-environment main + ``` + To update the GCP Cloud Run worker pool associated with an existing Worker Deployment Version: @@ -1771,6 +1822,33 @@ commands: When --aws-agentcore-endpoint-arn is specified, --aws-agentcore-assume-role-arn and --aws-agentcore-assume-role-external-id are required unless this flag is passed, in which case both must be omitted. + - name: modal-app-name + type: string + description: | + Name of the deployed Modal application containing the Worker + function. Required when configuring a Modal compute provider. + - name: modal-function-name + type: string + description: | + Name of the Modal function to invoke when there are no active pollers + for task queue targets in the Worker Deployment. Required when + configuring a Modal compute provider. + - name: modal-environment + type: string + description: | + Modal environment containing the deployed application. Required when + configuring a Modal compute provider. + - name: modal-workspace-id + type: string + description: | + Optional Modal workspace ID used to select the workspace's credential + grant. Omit when the server uses ambient Modal credentials. + - name: modal-version + type: string + description: | + Optional deployed Modal application version, expressed as a + non-negative integer. Omit to use the application's current deployed + version. - name: gcp-cloud-run-project type: string description: | @@ -1972,7 +2050,7 @@ commands: A Worker Deployment Version's compute configuration is made of one or more scaling groups. Each scaling group is identified by a key, uses a single compute provider, and may be limited to specific Task Queue - types: + types and regions: ``` temporal worker deployment version compute-config [command] [options] @@ -1990,6 +2068,18 @@ commands: --assume-role-external-id YourExternalID ``` + Create a Worker Deployment Version with compute configuration for a + Modal function that spawns a Worker in the Worker Deployment: + + ``` + temporal worker deployment version compute-config modal create \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --app-name YourModalApp \ + --function-name YourModalFunction \ + --environment YourModalEnvironment + ``` + Remove a scaling group from the compute configuration of a Version: ``` @@ -2013,8 +2103,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 Task Queue types, compute provider, and - scaler settings: + Deployment Version, with their Task Queue types, regions, compute + provider, and scaler settings: ``` temporal worker deployment version compute-config describe \ @@ -2150,10 +2240,25 @@ commands: --max-worker-lifetime-ms 300000 ``` - To update only the Task Queue types that a scaling group serves, supply - --task-queue-type without the other fields. The types passed replace - the existing ones, and the provider and scaling settings are not - changed: + To add a scaling group that serves only Workflow Task Queues 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 \ + --task-queue-type workflow \ + --function-arn YourLambdaFunctionARN \ + --assume-role-arn YourAssumeRoleARN \ + --assume-role-external-id YourExternalID + ``` + + To update only the Task Queue types or regions that a scaling group + serves, supply --task-queue-type or --region-id without the other + fields. The values passed replace the existing ones, and the provider + and scaling settings are not changed: ``` temporal worker deployment version compute-config aws-lambda update \ @@ -2164,8 +2269,8 @@ commands: --task-queue-type activity ``` - To make a scaling group serve every Task Queue type again, remove it - and set it again without --task-queue-type. + To make a scaling group serve every Task Queue type or region again, + remove it and set it again without --task-queue-type or --region-id. Provider fields are only required when changing the compute provider, and must be passed together. Changing the provider resets the scaling @@ -2192,6 +2297,168 @@ commands: queue targets in the Worker Deployment. Required when changing the compute provider. + - name: temporal worker deployment version compute-config modal + summary: Create or update Modal compute configuration (Experimental) + description: | + Modal commands set the compute configuration of a Worker Deployment + Version for a Modal function that spawns a Worker in the Worker + Deployment: + + ``` + temporal worker deployment version compute-config modal [command] + ``` + + Create a Worker Deployment Version with Modal compute configuration: + + ``` + temporal worker deployment version compute-config modal create \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --app-name YourModalApp \ + --function-name YourModalFunction \ + --environment YourModalEnvironment + ``` + + Update the Modal compute configuration of an existing Worker Deployment + Version: + + ``` + temporal worker deployment version compute-config modal update \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --app-name UpdatedModalApp \ + --function-name UpdatedModalFunction \ + --environment UpdatedModalEnvironment + ``` + + Note: This is an experimental feature and may change in the future. + + - name: temporal worker deployment version compute-config modal create + summary: Create a Version with Modal compute configuration (Experimental) + description: | + Create a new Worker Deployment Version with compute configuration for a + Modal function that spawns a Worker in the Worker Deployment: + + ``` + temporal worker deployment version compute-config modal create \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --app-name YourModalApp \ + --function-name YourModalFunction \ + --environment YourModalEnvironment + ``` + + To select a specific Modal workspace or deployed application version, + pass --workspace-id or --version. To tune when Workers are started, pass + any of the scaling flags. Each scaling flag that is not set keeps the + server default. + + The Worker Deployment must already exist; create it with + `temporal worker deployment create`. + + If a Worker Deployment Version with the supplied BuildID already exists, + this command will return an error. To update its compute configuration, + use `temporal worker deployment version compute-config modal update`. + + Note: This is an experimental feature and may change in the future. + option-sets: + - deployment-version + - scaling-group + - no-sync-scaler + options: + - name: app-name + type: string + required: true + description: | + Name of the deployed Modal application containing the Worker + function. + - name: function-name + type: string + required: true + description: | + Name of the Modal function to invoke when there are no active pollers + for Task Queue targets in the Worker Deployment. + - name: environment + type: string + required: true + description: Modal environment containing the deployed application. + - name: workspace-id + type: string + description: | + Optional Modal workspace ID used to select the workspace's credential + grant. Omit when the server uses ambient Modal credentials. + - name: version + type: string + description: | + Optional deployed Modal application version, expressed as a + non-negative integer. + + - name: temporal worker deployment version compute-config modal update + summary: Update Modal compute configuration for a Version (Experimental) + description: | + Update a scaling group in the compute configuration of a Worker + Deployment Version for a Modal function that spawns a Worker in the + Worker Deployment. Only the settings that are passed change, and the + other scaling groups are not affected. + + To update the Modal application and function associated with an existing + Worker Deployment Version: + + ``` + temporal worker deployment version compute-config modal update \ + --deployment-name YourDeploymentName \ + --build-id YourBuildID \ + --app-name UpdatedModalApp \ + --function-name UpdatedModalFunction \ + --environment UpdatedModalEnvironment + ``` + + To update only the scaling settings or Task Queue types, pass those flags + without provider fields. Provider fields require --app-name, + --function-name, and --environment together. Changing the provider resets + the scaling settings to the scaling flags passed with it. Optional + --workspace-id and --version values are omitted from the provider when + empty. + + If a Worker Deployment Version with the supplied BuildID does not exist, + this command will return an error. To create it, use + `temporal worker deployment version compute-config modal create`. + + Returns an error if all compute configuration fields are empty. + + Note: This is an experimental feature and may change in the future. + option-sets: + - deployment-version + - scaling-group + - no-sync-scaler + options: + - name: app-name + type: string + description: | + Name of the deployed Modal application containing the Worker + function. Required when changing the compute provider. + - name: function-name + type: string + description: | + Name of the Modal function to invoke when there are no active pollers + for Task Queue targets in the Worker Deployment. Required when + changing the compute provider. + - name: environment + type: string + description: | + Modal environment containing the deployed application. Required when + changing the compute provider. + - name: workspace-id + type: string + description: | + Optional Modal workspace ID used to select the workspace's credential + grant. Omit when the server uses ambient Modal credentials. + - name: version + type: string + description: | + Optional deployed Modal application version, expressed as a + non-negative integer. + - name: temporal worker deployment version compute-config remove summary: Remove compute configuration from a Version (Experimental) description: | @@ -5839,6 +6106,16 @@ 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 one of these regions, and takes precedence there over + scaling groups without regions. A scaling group created without + this flag can be used in any region. When updating a scaling group, + the regions passed replace its existing ones. + Can be passed multiple times. - name: task-queue-type type: string-enum[] description: |