diff --git a/go.mod b/go.mod index 7cea3921..2d733bf1 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/temporalio/cli -go 1.22.3 +go 1.22.6 + +toolchain go1.23.2 require ( github.com/alitto/pond v1.9.1 @@ -15,10 +17,10 @@ require ( github.com/spf13/pflag v1.0.5 github.com/stretchr/testify v1.9.0 github.com/temporalio/ui-server/v2 v2.30.3 - go.temporal.io/api v1.38.0 - go.temporal.io/sdk v1.29.0 - go.temporal.io/server v1.25.0 - google.golang.org/grpc v1.65.0 + go.temporal.io/api v1.39.1-0.20241015190548-07c3704f5f12 + go.temporal.io/sdk v1.29.2-0.20241008230001-c82a8ac11cc6 + go.temporal.io/server v1.26.2-122.0.0.20241017144430-3615581c0cef + google.golang.org/grpc v1.66.0 google.golang.org/protobuf v1.34.2 gopkg.in/yaml.v3 v3.0.1 ) @@ -40,7 +42,7 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/coreos/go-oidc/v3 v3.1.0 // indirect - github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect + github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect github.com/emirpasic/gods v1.18.1 // indirect github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -81,7 +83,6 @@ require ( github.com/mattn/go-runewidth v0.0.15 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/ncruces/go-strftime v0.1.9 // indirect - github.com/nexus-rpc/sdk-go v0.0.10 // indirect github.com/olivere/elastic/v7 v7.0.32 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pborman/uuid v1.2.1 // indirect @@ -124,6 +125,7 @@ require ( go.uber.org/atomic v1.11.0 // indirect go.uber.org/dig v1.17.1 // indirect go.uber.org/fx v1.22.0 // indirect + go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.26.0 // indirect @@ -136,8 +138,8 @@ require ( golang.org/x/time v0.5.0 // indirect google.golang.org/api v0.182.0 // indirect google.golang.org/genproto v0.0.0-20240528184218-531527333157 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 // indirect gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/square/go-jose.v2 v2.6.0 // indirect diff --git a/go.sum b/go.sum index 9d26c831..1836b7ca 100644 --- a/go.sum +++ b/go.sum @@ -61,8 +61,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dgryski/go-farm v0.0.0-20140601200337-fc41e106ee0e/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 h1:fAjc9m62+UWV/WAFKLNi6ZS0675eEUC9y3AlwSbQu1Y= -github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= @@ -348,12 +348,12 @@ go.opentelemetry.io/otel/trace v1.27.0 h1:IqYb813p7cmbHk0a5y6pD5JPakbVfftRXABGt5 go.opentelemetry.io/otel/trace v1.27.0/go.mod h1:6RiD1hkAprV4/q+yd2ln1HG9GoPx39SuvvstaLBl+l4= go.opentelemetry.io/proto/otlp v1.2.0 h1:pVeZGk7nXDC9O2hncA6nHldxEjm6LByfA2aN8IOkz94= go.opentelemetry.io/proto/otlp v1.2.0/go.mod h1:gGpR8txAl5M03pDhMC79G6SdqNV26naRm/KDsgaHD8A= -go.temporal.io/api v1.38.0 h1:L5i+Ai7UoBa2Gq/goVHLY32064AgawxPDLkKm4I7fu4= -go.temporal.io/api v1.38.0/go.mod h1:fmh06EjstyrPp6SHbjJo7yYHBfHamPE4SytM+2NRejc= -go.temporal.io/sdk v1.29.0 h1:AHObeNFFxVlnaj7jql3Bjd4B0bMBaXkywJU0uVIPgJo= -go.temporal.io/sdk v1.29.0/go.mod h1:kp//DRvn3CqQVBCtjL51Oicp9wrZYB2s6row1UgzcKQ= -go.temporal.io/server v1.25.0 h1:HwP7musDblTbobv8727t5riWB5T1UKqUZBLmIrWFwF8= -go.temporal.io/server v1.25.0/go.mod h1:+8eYt3bSdHzPDMyEW3RgtsbAJRblhUEH0PVRSPiMyUs= +go.temporal.io/api v1.39.1-0.20241015190548-07c3704f5f12 h1:/NVYBOJEDAShJ0cJFgESDy9w1XjhJyrg3+L91SOXwAc= +go.temporal.io/api v1.39.1-0.20241015190548-07c3704f5f12/go.mod h1:1WwYUMo6lao8yl0371xWUm13paHExN5ATYT/B7QtFis= +go.temporal.io/sdk v1.29.2-0.20241008230001-c82a8ac11cc6 h1:SlZapy1jTeSDEL/0WxKyp2Jw7i/GxdFtqVm1YeQ2tzY= +go.temporal.io/sdk v1.29.2-0.20241008230001-c82a8ac11cc6/go.mod h1:R52PRhHZMkHJqrWRPBom0UAqcexPUvDpcf0qbAGwLos= +go.temporal.io/server v1.26.2-122.0.0.20241017144430-3615581c0cef h1:vIbwm1Op+dHIe1zHFV/RtSSCcrN23ZIiTnRZKcMFQGI= +go.temporal.io/server v1.26.2-122.0.0.20241017144430-3615581c0cef/go.mod h1:30kg/Vf1w5iDWCPzapzUYU/5LkEuOneE4Rg/r6a+qMA= go.temporal.io/version v0.3.0 h1:dMrei9l9NyHt8nG6EB8vAwDLLTwx2SvRyucCSumAiig= go.temporal.io/version v0.3.0/go.mod h1:UA9S8/1LaKYae6TyD9NaPMJTZb911JcbqghI2CBSP78= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -367,6 +367,8 @@ go.uber.org/fx v1.22.0/go.mod h1:HT2M7d7RHo+ebKGh9NRcrsrHHfpZ60nW3QRubMRfv48= go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= +go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= +go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.7.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= @@ -527,18 +529,18 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20240528184218-531527333157 h1:u7WMYrIrVvs0TF5yaKwKNbcJyySYf+HAIFXxWltJOXE= google.golang.org/genproto v0.0.0-20240528184218-531527333157/go.mod h1:ubQlAQnzejB8uZzszhrTCU2Fyp6Vi7ZE5nn0c3W8+qQ= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd h1:BBOTEWLuuEGQy9n1y9MhVJ9Qt0BDu21X8qZs71/uPZo= -google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:fO8wJzT2zbQbAjbIoos1285VfEIYKDDY+Dt+WpTkh6g= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd h1:6TEm2ZxXoQmFWFlt1vNxvVOa1Q0dXFQD1m/rYjXmS0E= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1 h1:hjSy6tcFQZ171igDaN5QHOw2n6vx40juYbC/x67CEhc= +google.golang.org/genproto/googleapis/api v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:qpvKtACPCQhAdu3PyQgV4l3LMXZEtft7y8QcarRsp9I= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1 h1:pPJltXNxVzT4pK9yD8vR9X75DaWYYmLGMsEvBfFQZzQ= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240903143218-8af14fe29dc1/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= +google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= +google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= diff --git a/temporalcli/commands.activity.go b/temporalcli/commands.activity.go index 6750d0b8..e9e354c6 100644 --- a/temporalcli/commands.activity.go +++ b/temporalcli/commands.activity.go @@ -3,9 +3,13 @@ package temporalcli import ( "fmt" + activitypb "go.temporal.io/api/activity/v1" "go.temporal.io/api/common/v1" "go.temporal.io/api/failure/v1" + taskqueuepn "go.temporal.io/api/taskqueue/v1" "go.temporal.io/api/workflowservice/v1" + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/fieldmaskpb" ) func (c *TemporalActivityCompleteCommand) run(cctx *CommandContext, args []string) error { @@ -70,3 +74,83 @@ func (c *TemporalActivityFailCommand) run(cctx *CommandContext, args []string) e } return nil } + +func (c *TemporalActivityUpdateCommand) run(cctx *CommandContext, args []string) error { + cl, err := c.Parent.ClientOptions.dialClient(cctx) + if err != nil { + return err + } + defer cl.Close() + + updatePath := []string{} + activityOptions := &activitypb.ActivityOptions{} + + if c.Command.Flags().Changed("task-queue") { + activityOptions.TaskQueue = &taskqueuepn.TaskQueue{Name: c.TaskQueue} + updatePath = append(updatePath, "task_queue_name") + } + + if c.Command.Flags().Changed("schedule-to-close-timeout") { + activityOptions.ScheduleToCloseTimeout = durationpb.New(c.ScheduleToCloseTimeout.Duration()) + updatePath = append(updatePath, "schedule_to_close_timeout") + } + + if c.Command.Flags().Changed("schedule-to-start-timeout") { + activityOptions.ScheduleToStartTimeout = durationpb.New(c.ScheduleToStartTimeout.Duration()) + updatePath = append(updatePath, "schedule_to_start_timeout") + } + + if c.Command.Flags().Changed("start-to-close-timeout") { + activityOptions.StartToCloseTimeout = durationpb.New(c.StartToCloseTimeout.Duration()) + updatePath = append(updatePath, "start_to_close_timeout") + } + + if c.Command.Flags().Changed("heartbeat-timeout") { + activityOptions.HeartbeatTimeout = durationpb.New(c.HeartbeatTimeout.Duration()) + updatePath = append(updatePath, "heartbeat_timeout") + } + + if c.Command.Flags().Changed("retry-initial-interval") || + c.Command.Flags().Changed("retry-maximum-interval") || + c.Command.Flags().Changed("retry-backoff-coefficient") || + c.Command.Flags().Changed("retry-maximum-attempts") { + activityOptions.RetryPolicy = &common.RetryPolicy{} + } + + if c.Command.Flags().Changed("retry-initial-interval") { + activityOptions.RetryPolicy.InitialInterval = durationpb.New(c.RetryInitialInterval.Duration()) + updatePath = append(updatePath, "retry_policy.initial_interval") + } + + if c.Command.Flags().Changed("retry-maximum-interval") { + activityOptions.RetryPolicy.MaximumInterval = durationpb.New(c.RetryMaximumInterval.Duration()) + updatePath = append(updatePath, "retry_policy.maximum_interval") + } + + if c.Command.Flags().Changed("retry-backoff-coefficient") { + activityOptions.RetryPolicy.BackoffCoefficient = float64(c.RetryBackoffCoefficient) + updatePath = append(updatePath, "retry_policy.backoff_coefficient") + } + + if c.Command.Flags().Changed("retry-maximum-attempts") { + activityOptions.RetryPolicy.MaximumAttempts = int32(c.RetryMaximumAttempts) + updatePath = append(updatePath, "retry_policy.maximum_attempts") + } + + _, err = cl.WorkflowService().UpdateActivityOptionsById(cctx, &workflowservice.UpdateActivityOptionsByIdRequest{ + Namespace: c.Parent.Namespace, + WorkflowId: c.WorkflowId, + RunId: c.RunId, + ActivityId: c.ActivityId, + ActivityOptions: activityOptions, + UpdateMask: &fieldmaskpb.FieldMask{ + Paths: updatePath, + }, + + Identity: c.Identity, + }) + if err != nil { + return fmt.Errorf("unable to update Activity options: %w", err) + } + return nil +} diff --git a/temporalcli/commands.activity_test.go b/temporalcli/commands.activity_test.go index c5c11da6..16cf662a 100644 --- a/temporalcli/commands.activity_test.go +++ b/temporalcli/commands.activity_test.go @@ -106,6 +106,32 @@ func (s *SharedServerSuite) TestActivity_Fail_InvalidDetail() { s.Nil(failed) } +func (s *SharedServerSuite) TestActivityOptionsUpdate_Accept() { + run := s.waitActivityStarted() + wid := run.GetID() + aid := "dev-activity-id" + identity := "MyIdentity" + + res := s.Execute( + "activity", "update", + "--activity-id", aid, + "--workflow-id", wid, + "--run-id", run.GetRunID(), + "--identity", identity, + "--task-queue", "new-task-queue", + "--schedule-to-close-timeout", "60", + "--schedule-to-start-timeout", "5", + "--start-to-close-timeout", "10", + "--heartbeat-timeout", "20", + "--retry-initial-interval", "5", + "--retry-maximum-interval", "60", + "--retry-backoff-coefficient", "2", + "--retry-maximum-attempts", "5", + ) + // atm, the command is not implemented + s.Error(res.Err) +} + // Test helpers func (s *SharedServerSuite) waitActivityStarted() client.WorkflowRun { diff --git a/temporalcli/commands.gen.go b/temporalcli/commands.gen.go index a56d6d3c..63af439c 100644 --- a/temporalcli/commands.gen.go +++ b/temporalcli/commands.gen.go @@ -326,15 +326,16 @@ func NewTemporalActivityCommand(cctx *CommandContext, parent *TemporalCommand) * var s TemporalActivityCommand s.Parent = parent s.Command.Use = "activity" - s.Command.Short = "Complete or fail an Activity" + s.Command.Short = "Complete, update or fail an Activity" if hasHighlighting { - s.Command.Long = "Update an Activity's state to completed or failed. This marks an Activity\nas successfully finished or as having encountered an error:\n\n\x1b[1mtemporal activity complete \\\n --activity-id=YourActivityId \\\n --workflow-id=YourWorkflowId \\\n --result='{\"YourResultKey\": \"YourResultValue\"}'\x1b[0m" + s.Command.Long = "Update an Activity's options or update an Activity's state to completed or failed. \nUpdating activity state marks an Activity as successfully finished or as having encountered an error,\n\n\x1b[1mtemporal activity complete \\\n --activity-id=YourActivityId \\\n --workflow-id=YourWorkflowId \\\n --result='{\"YourResultKey\": \"YourResultValue\"}'\x1b[0m" } else { - s.Command.Long = "Update an Activity's state to completed or failed. This marks an Activity\nas successfully finished or as having encountered an error:\n\n```\ntemporal activity complete \\\n --activity-id=YourActivityId \\\n --workflow-id=YourWorkflowId \\\n --result='{\"YourResultKey\": \"YourResultValue\"}'\n```" + s.Command.Long = "Update an Activity's options or update an Activity's state to completed or failed. \nUpdating activity state marks an Activity as successfully finished or as having encountered an error,\n\n```\ntemporal activity complete \\\n --activity-id=YourActivityId \\\n --workflow-id=YourWorkflowId \\\n --result='{\"YourResultKey\": \"YourResultValue\"}'\n```" } s.Command.Args = cobra.NoArgs s.Command.AddCommand(&NewTemporalActivityCompleteCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityFailCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityUpdateCommand(cctx, &s).Command) s.ClientOptions.buildFlags(cctx, s.Command.PersistentFlags()) return &s } @@ -410,6 +411,62 @@ func NewTemporalActivityFailCommand(cctx *CommandContext, parent *TemporalActivi return &s } +type TemporalActivityUpdateCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + WorkflowReferenceOptions + ActivityId string + TaskQueue string + ScheduleToCloseTimeout Duration + ScheduleToStartTimeout Duration + StartToCloseTimeout Duration + HeartbeatTimeout Duration + RetryInitialInterval Duration + RetryMaximumInterval Duration + RetryBackoffCoefficient float32 + RetryMaximumAttempts int + Identity string +} + +func NewTemporalActivityUpdateCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityUpdateCommand { + var s TemporalActivityUpdateCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "update [flags]" + s.Command.Short = "Update Activity options" + if hasHighlighting { + s.Command.Long = "Update Activity options. Specify the Activity and Workflow IDs, and options you want to update. \nUpdates are incremental, only changing the specified options. \n\n\x1b[1mtemporal activity update \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --task-queue NewTaskQueueName \\\n --schedule-to-close-timeout DURATION\\\n --schedule-to-start-timeout DURATION\\\n --start-to-close-timeout DURATION\\\n --heartbeat-timeout DURATION\\\n --retry-initial-interval DURATION\\\n --retry-maximum-interval DURATION\\\n --retry-backoff-coefficient NewBackoffCoefficient\\\n --retry-maximum-attempts NewMaximumAttempts\"\x1b[0m" + } else { + s.Command.Long = "Update Activity options. Specify the Activity and Workflow IDs, and options you want to update. \nUpdates are incremental, only changing the specified options. \n\n```\ntemporal activity update \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --task-queue NewTaskQueueName \\\n --schedule-to-close-timeout DURATION\\\n --schedule-to-start-timeout DURATION\\\n --start-to-close-timeout DURATION\\\n --heartbeat-timeout DURATION\\\n --retry-initial-interval DURATION\\\n --retry-maximum-interval DURATION\\\n --retry-backoff-coefficient NewBackoffCoefficient\\\n --retry-maximum-attempts NewMaximumAttempts\"\n\n```" + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVar(&s.ActivityId, "activity-id", "", "Activity ID. Required.") + _ = cobra.MarkFlagRequired(s.Command.Flags(), "activity-id") + s.Command.Flags().StringVar(&s.TaskQueue, "task-queue", "", "Name of the task queue for the Activity.") + s.ScheduleToCloseTimeout = 0 + s.Command.Flags().Var(&s.ScheduleToCloseTimeout, "schedule-to-close-timeout", "Indicates how long the caller is willing to wait for an activity completion. Limits how long retries will be attempted.") + s.ScheduleToStartTimeout = 0 + s.Command.Flags().Var(&s.ScheduleToStartTimeout, "schedule-to-start-timeout", "Limits time an activity task can stay in a task queue before a worker picks it up. This timeout is always non retryable, as all a retry would achieve is to put it back into the same queue. Defaults to `schedule_to_close_timeout` or workflow execution timeout if not specified.") + s.StartToCloseTimeout = 0 + s.Command.Flags().Var(&s.StartToCloseTimeout, "start-to-close-timeout", "Maximum time an activity is allowed to execute after being picked up by a worker. This timeout is always retryable.") + s.HeartbeatTimeout = 0 + s.Command.Flags().Var(&s.HeartbeatTimeout, "heartbeat-timeout", "Maximum permitted time between successful worker heartbeats.") + s.RetryInitialInterval = 0 + s.Command.Flags().Var(&s.RetryInitialInterval, "retry-initial-interval", "Interval of the first retry. If retryBackoffCoefficient is 1.0 then it is used for all retries.") + s.RetryMaximumInterval = 0 + s.Command.Flags().Var(&s.RetryMaximumInterval, "retry-maximum-interval", "Maximum interval between retries. Exponential backoff leads to interval increase. This value is the cap of the increase.") + s.Command.Flags().Float32Var(&s.RetryBackoffCoefficient, "retry-backoff-coefficient", 0, "Coefficient used to calculate the next retry interval. The next retry interval is previous interval multiplied by the coefficient. Must be 1 or larger.") + s.Command.Flags().IntVar(&s.RetryMaximumAttempts, "retry-maximum-attempts", 0, "Maximum number of attempts. When exceeded the retries stop even if not expired yet. Setting this value to 1 disables retries. Setting this value to 0 means unlimited attempts(up to the timeouts).") + s.Command.Flags().StringVar(&s.Identity, "identity", "", "Identity of the user submitting this request.") + s.WorkflowReferenceOptions.buildFlags(cctx, 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 TemporalBatchCommand struct { Parent *TemporalCommand Command cobra.Command diff --git a/temporalcli/commandsgen/commands.yml b/temporalcli/commandsgen/commands.yml index e03e572b..1337b3b1 100644 --- a/temporalcli/commandsgen/commands.yml +++ b/temporalcli/commandsgen/commands.yml @@ -200,10 +200,10 @@ commands: description: Timeout for the span of a command. - name: temporal activity - summary: Complete or fail an Activity + summary: Complete, update or fail an Activity description: | - Update an Activity's state to completed or failed. This marks an Activity - as successfully finished or as having encountered an error: + Update an Activity's options or update an Activity's state to completed or failed. + Updating activity state marks an Activity as successfully finished or as having encountered an error, ``` temporal activity complete \ @@ -221,6 +221,7 @@ commands: keywords: - activity - activity complete + - activity update - activity execution - activity fail - cli reference @@ -283,6 +284,82 @@ commands: option-sets: - workflow reference + - name: temporal activity update + summary: Update Activity options + description: | + Update Activity options. Specify the Activity and Workflow IDs, and options you want to update. + Updates are incremental, only changing the specified options. + + ``` + temporal activity update \ + --activity-id YourActivityId \ + --workflow-id YourWorkflowId \ + --task-queue NewTaskQueueName \ + --schedule-to-close-timeout DURATION\ + --schedule-to-start-timeout DURATION\ + --start-to-close-timeout DURATION\ + --heartbeat-timeout DURATION\ + --retry-initial-interval DURATION\ + --retry-maximum-interval DURATION\ + --retry-backoff-coefficient NewBackoffCoefficient\ + --retry-maximum-attempts NewMaximumAttempts" + + ``` + options: + - name: activity-id + type: string + description: Activity ID. + required: true + - name: task-queue + type: string + description: Name of the task queue for the Activity. + - name: schedule-to-close-timeout + type: duration + description: | + Indicates how long the caller is willing to wait for an activity completion. + Limits how long retries will be attempted. + - name: schedule-to-start-timeout + type: duration + description: | + Limits time an activity task can stay in a task queue before a worker picks it up. + This timeout is always non retryable, as all a retry would achieve is to put it back into the same + queue. Defaults to `schedule_to_close_timeout` or workflow execution timeout if not specified. + - name: start-to-close-timeout + type: duration + description: | + Maximum time an activity is allowed to execute after being picked up by a worker. This timeout is always retryable. + - name: heartbeat-timeout + type: duration + description: | + Maximum permitted time between successful worker heartbeats. + - name: retry-initial-interval + type: duration + description: | + Interval of the first retry. If retryBackoffCoefficient is 1.0 then it is used for all retries. + - name: retry-maximum-interval + type: duration + description: | + Maximum interval between retries. Exponential backoff leads to interval increase. + This value is the cap of the increase. + - name: retry-backoff-coefficient + type: float + description: | + Coefficient used to calculate the next retry interval. + The next retry interval is previous interval multiplied by the coefficient. + Must be 1 or larger. + - name: retry-maximum-attempts + type: int + description: | + Maximum number of attempts. When exceeded the retries stop even if not expired yet. + Setting this value to 1 disables retries. Setting this value to 0 means unlimited attempts(up to the timeouts). + - name: identity + type: string + description: Identity of the user submitting this request. + option-sets: + - workflow reference + + + - name: temporal batch summary: Manage running batch jobs description: | diff --git a/temporalcli/devserver/server.go b/temporalcli/devserver/server.go index 60effbb4..90bb138d 100644 --- a/temporalcli/devserver/server.go +++ b/temporalcli/devserver/server.go @@ -340,7 +340,11 @@ func (s *StartOptions) buildSQLConfig() (*config.SQL, error) { // Create namespaces namespaces := make([]*sqliteschema.NamespaceConfig, len(s.Namespaces)) for i, ns := range s.Namespaces { - namespaces[i] = sqlite.NewNamespaceConfig(s.CurrentClusterName, ns, false) + namespaceConfig, err := sqlite.NewNamespaceConfig(s.CurrentClusterName, ns, false, nil) + if err != nil { + return nil, fmt.Errorf("failed getting namespace config: %w", err) + } + namespaces[i] = namespaceConfig } if err := sqliteschema.CreateNamespaces(&conf, namespaces...); err != nil { return nil, fmt.Errorf("failed creating namespaces: %w", err)