diff --git a/go.mod b/go.mod index 90fe02df5..596e8ad2c 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/temporalio/cli -go 1.26.3 +go 1.26.4 require ( github.com/BurntSushi/toml v1.4.0 @@ -17,13 +17,13 @@ require ( github.com/stretchr/testify v1.11.1 github.com/temporalio/cli/cliext v0.0.0 github.com/temporalio/ui-server/v2 v2.49.1 - go.temporal.io/api v1.62.13 + go.temporal.io/api v1.62.15-0.20260615235047-378792ab2240 go.temporal.io/sdk v1.44.1 go.temporal.io/sdk/contrib/envconfig v1.0.2 - go.temporal.io/server v1.32.0-157.0 + go.temporal.io/server v1.29.0-135.0.0.20260616172559-0f70f6096799 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/mod v0.35.0 - golang.org/x/term v0.42.0 + golang.org/x/term v0.43.0 golang.org/x/tools v0.44.0 google.golang.org/grpc v1.80.0 google.golang.org/protobuf v1.36.11 @@ -201,12 +201,12 @@ require ( go.uber.org/zap v1.27.1 // indirect go.yaml.in/yaml/v2 v2.4.4 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.50.0 // indirect - golang.org/x/net v0.53.0 // indirect + golang.org/x/crypto v0.52.0 // indirect + golang.org/x/net v0.55.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect - golang.org/x/sys v0.43.0 // indirect - golang.org/x/text v0.36.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.37.0 // indirect golang.org/x/time v0.15.0 // indirect google.golang.org/api v0.276.0 // indirect google.golang.org/genproto v0.0.0-20260420184626-e10c466a9529 // indirect diff --git a/go.sum b/go.sum index 01c1676b9..6529d769c 100644 --- a/go.sum +++ b/go.sum @@ -469,16 +469,16 @@ go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09 go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= 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.62.13 h1:xMa8Nt5oAMX+LvlCJA44wjTCc1H09i2rG9poB1/xvH4= -go.temporal.io/api v1.62.13/go.mod h1:0k75tRljEuELWGeXjEZZO7zYqBln4+1FrG6+IMOMy7Q= +go.temporal.io/api v1.62.15-0.20260615235047-378792ab2240 h1:Up/CNfkScGxN1TdrGZ3ez+0k6MIIhuhlbBgdZnrPhm0= +go.temporal.io/api v1.62.15-0.20260615235047-378792ab2240/go.mod h1:0k75tRljEuELWGeXjEZZO7zYqBln4+1FrG6+IMOMy7Q= go.temporal.io/auto-scaled-workers v0.0.0-20260407181057-edd947d743d2 h1:1hKeH3GyR6YD6LKMHGCZ76t6h1Sgha0hXVQBxWi3dlQ= go.temporal.io/auto-scaled-workers v0.0.0-20260407181057-edd947d743d2/go.mod h1:T8dnzVPeO+gaUTj9eDgm/lT2lZH4+JXNvrGaQGyVi50= go.temporal.io/sdk v1.44.1 h1:Mt2OZLZpqkzDIdg9YyQzO0Rb/HqCDnnqHlIAGAJ5gqM= go.temporal.io/sdk v1.44.1/go.mod h1:vkApR12F9/Y8OR+hkxe7WyXQFuCX6clhzqnAk6rzDAM= 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-157.0 h1:nzFqNwx+5lXsT0/DSiFyR5vHMnDcT3PVAvmRDqCUn38= -go.temporal.io/server v1.32.0-157.0/go.mod h1:a76wf30/s28JXh+3nDQtQi8KzOfRQEddpebvmr/oQL4= +go.temporal.io/server v1.29.0-135.0.0.20260616172559-0f70f6096799 h1:RAdcDcpr3gqS4EfO+/7uq4XFz97RDXseH2BQQN+adao= +go.temporal.io/server v1.29.0-135.0.0.20260616172559-0f70f6096799/go.mod h1:/9DA479u5Cas9fZ/c5VWJF2SjA7VTeg/tRWFshr3Lho= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -509,8 +509,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= -golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= +golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= +golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -543,8 +543,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.53.0 h1:d+qAbo5L0orcWAr0a9JweQpjXF19LMXJE8Ey7hwOdUA= -golang.org/x/net v0.53.0/go.mod h1:JvMuJH7rrdiCfbeHoo3fCQU24Lf5JJwT9W3sJFulfgs= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -571,15 +571,15 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= -golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= -golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= +golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -587,8 +587,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= -golang.org/x/text v0.36.0 h1:JfKh3XmcRPqZPKevfXVpI1wXPTqbkE5f7JA92a55Yxg= -golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= +golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= +golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/temporalcli/commands.activity.go b/internal/temporalcli/commands.activity.go index 582f5d622..5d876fb56 100644 --- a/internal/temporalcli/commands.activity.go +++ b/internal/temporalcli/commands.activity.go @@ -40,6 +40,23 @@ type ( } ) +// Targeting errors for the activity operate commands. They name every flag a +// caller can use so the failure tells the user exactly how to retarget: +// - a single Activity: --activity-id, optionally with --workflow-id (workflow +// Activity) and/or --run-id (specific run; standalone when no --workflow-id) +// - a batch of workflow Activities: --query +var ( + // errActivityTarget is used by the operations that support batching + // (unpause, reset, update-options). + errActivityTarget = errors.New("must specify --activity-id to target a single Activity " + + "(optionally with --workflow-id and/or --run-id), or --query to target a batch of Activities") + + // errPauseActivityTarget is the pause equivalent; pause has no --query + // (batch) mode. + errPauseActivityTarget = errors.New("must specify --activity-id to pause an Activity " + + "(optionally with --workflow-id and/or --run-id)") +) + func (c *TemporalActivityStartCommand) run(cctx *CommandContext, args []string) error { cl, err := dialClient(cctx, &c.Parent.ClientOptions) if err != nil { @@ -704,28 +721,42 @@ func (c *TemporalActivityUpdateOptionsCommand) run(cctx *CommandContext, args [] Rps: c.Rps, } - exec, batchReq, err := opts.workflowExecOrBatch(cctx, c.Parent.Namespace, cl, singleOrBatchOverrides{}) - if err != nil { - return err + // Target a workflow Activity (--workflow-id), a standalone Activity (no + // --workflow-id; the latest run unless --run-id is set), or a batch of + // workflow Activities (--query). The server routes to standalone-activity + // handling when the workflow ID is empty, so standalone Activities take the + // single-execution path below. + var exec *common.WorkflowExecution + var batchReq *workflowservice.StartBatchOperationRequest + if c.WorkflowId == "" && c.Query == "" { + if c.ActivityId == "" { + return errActivityTarget + } + exec = &common.WorkflowExecution{RunId: c.RunId} + } else { + exec, batchReq, err = opts.workflowExecOrBatch(cctx, c.Parent.Namespace, cl, singleOrBatchOverrides{}) + if err != nil { + return err + } } if exec != nil { if c.ActivityId == "" { - return fmt.Errorf("either --activity-id and --workflow-id, or --query must be set") - } - result, err := cl.WorkflowService().UpdateActivityOptions(cctx, &workflowservice.UpdateActivityOptionsRequest{ - Namespace: c.Parent.Namespace, - Execution: &common.WorkflowExecution{ - WorkflowId: c.WorkflowId, - RunId: c.RunId, - }, - Activity: &workflowservice.UpdateActivityOptionsRequest_Id{Id: c.ActivityId}, - ActivityOptions: activityOptions, - UpdateMask: &fieldmaskpb.FieldMask{ - Paths: updatePath, - }, - Identity: c.Parent.Identity, - }) + return errActivityTarget + } + result, err := cl.WorkflowService().UpdateActivityExecutionOptions( + cctx, + &workflowservice.UpdateActivityExecutionOptionsRequest{ + Namespace: c.Parent.Namespace, + WorkflowId: c.WorkflowId, + RunId: c.RunId, + ActivityId: c.ActivityId, + ActivityOptions: activityOptions, + UpdateMask: &fieldmaskpb.FieldMask{ + Paths: updatePath, + }, + Identity: c.Parent.Identity, + }) if err != nil { return fmt.Errorf("unable to update Activity options: %w", err) } @@ -768,8 +799,12 @@ func (c *TemporalActivityUpdateOptionsCommand) run(cctx *CommandContext, args [] func (c *TemporalActivityPauseCommand) run(cctx *CommandContext, args []string) error { if c.ActivityId == "" { - return fmt.Errorf("Activity Id must be specified") + return errPauseActivityTarget } + // Set --workflow-id to target a workflow Activity. Omit it to target a + // standalone Activity by --activity-id (and optionally --run-id for a + // specific run); the server routes to standalone-activity handling when the + // workflow ID is empty. cl, err := dialClient(cctx, &c.Parent.ClientOptions) if err != nil { @@ -777,21 +812,19 @@ func (c *TemporalActivityPauseCommand) run(cctx *CommandContext, args []string) } defer cl.Close() - request := &workflowservice.PauseActivityRequest{ - Namespace: c.Parent.Namespace, - Execution: &common.WorkflowExecution{ - WorkflowId: c.WorkflowId, - RunId: c.RunId, - }, - Identity: c.Identity, - Reason: c.Reason, - Activity: &workflowservice.PauseActivityRequest_Id{Id: c.ActivityId}, + request := &workflowservice.PauseActivityExecutionRequest{ + Namespace: c.Parent.Namespace, + WorkflowId: c.WorkflowId, + ActivityId: c.ActivityId, + RunId: c.RunId, + Identity: c.Identity, + Reason: c.Reason, } if request.Identity == "" { request.Identity = c.Parent.Identity } - _, err = cl.WorkflowService().PauseActivity(cctx, request) + _, err = cl.WorkflowService().PauseActivityExecution(cctx, request) if err != nil { return fmt.Errorf("unable to pause Activity: %w", err) } @@ -817,30 +850,42 @@ func (c *TemporalActivityUnpauseCommand) run(cctx *CommandContext, args []string Rps: c.Rps, } - exec, batchReq, err := opts.workflowExecOrBatch(cctx, c.Parent.Namespace, cl, singleOrBatchOverrides{}) - if err != nil { - return err + // Target a workflow Activity (--workflow-id), a standalone Activity (no + // --workflow-id; the latest run unless --run-id is set), or a batch of + // workflow Activities (--query). The server routes to standalone-activity + // handling when the workflow ID is empty, so standalone Activities take the + // single-execution path below. + var exec *common.WorkflowExecution + var batchReq *workflowservice.StartBatchOperationRequest + if c.WorkflowId == "" && c.Query == "" { + if c.ActivityId == "" { + return errActivityTarget + } + exec = &common.WorkflowExecution{RunId: c.RunId} + } else { + exec, batchReq, err = opts.workflowExecOrBatch(cctx, c.Parent.Namespace, cl, singleOrBatchOverrides{}) + if err != nil { + return err + } } if exec != nil { // single workflow operation if c.ActivityId == "" { - return fmt.Errorf("either --activity-id and --workflow-id, or --query must be set") + return errActivityTarget } - request := &workflowservice.UnpauseActivityRequest{ - Namespace: c.Parent.Namespace, - Execution: &common.WorkflowExecution{ - WorkflowId: c.WorkflowId, - RunId: c.RunId, - }, + request := &workflowservice.UnpauseActivityExecutionRequest{ + Namespace: c.Parent.Namespace, + WorkflowId: c.WorkflowId, + ActivityId: c.ActivityId, + RunId: c.RunId, ResetAttempts: c.ResetAttempts, ResetHeartbeat: c.ResetHeartbeats, Jitter: durationpb.New(c.Jitter.Duration()), Identity: c.Parent.Identity, - Activity: &workflowservice.UnpauseActivityRequest_Id{Id: c.ActivityId}, } - _, err = cl.WorkflowService().UnpauseActivity(cctx, request) + _, err = cl.WorkflowService().UnpauseActivityExecution(cctx, request) if err != nil { return fmt.Errorf("unable to unpause an Activity: %w", err) } @@ -883,29 +928,41 @@ func (c *TemporalActivityResetCommand) run(cctx *CommandContext, args []string) Rps: c.Rps, } - exec, batchReq, err := opts.workflowExecOrBatch(cctx, c.Parent.Namespace, cl, singleOrBatchOverrides{}) - if err != nil { - return err + // Target a workflow Activity (--workflow-id), a standalone Activity (no + // --workflow-id; the latest run unless --run-id is set), or a batch of + // workflow Activities (--query). The server routes to standalone-activity + // handling when the workflow ID is empty, so standalone Activities take the + // single-execution path below. + var exec *common.WorkflowExecution + var batchReq *workflowservice.StartBatchOperationRequest + if c.WorkflowId == "" && c.Query == "" { + if c.ActivityId == "" { + return errActivityTarget + } + exec = &common.WorkflowExecution{RunId: c.RunId} + } else { + exec, batchReq, err = opts.workflowExecOrBatch(cctx, c.Parent.Namespace, cl, singleOrBatchOverrides{}) + if err != nil { + return err + } } if exec != nil { // single workflow operation if c.ActivityId == "" { - return fmt.Errorf("either --activity-id and --workflow-id, or --query must be set") + return errActivityTarget } - request := &workflowservice.ResetActivityRequest{ - Activity: &workflowservice.ResetActivityRequest_Id{Id: c.ActivityId}, - Namespace: c.Parent.Namespace, - Execution: &common.WorkflowExecution{ - WorkflowId: c.WorkflowId, - RunId: c.RunId, - }, + request := &workflowservice.ResetActivityExecutionRequest{ + Namespace: c.Parent.Namespace, + WorkflowId: c.WorkflowId, + ActivityId: c.ActivityId, + RunId: c.RunId, Identity: c.Parent.Identity, KeepPaused: c.KeepPaused, ResetHeartbeat: c.ResetHeartbeats, } - resp, err := cl.WorkflowService().ResetActivity(cctx, request) + resp, err := cl.WorkflowService().ResetActivityExecution(cctx, request) if err != nil { return fmt.Errorf("unable to reset an Activity: %w", err) } diff --git a/internal/temporalcli/commands.activity_test.go b/internal/temporalcli/commands.activity_test.go index ec6b50a4f..744c39096 100644 --- a/internal/temporalcli/commands.activity_test.go +++ b/internal/temporalcli/commands.activity_test.go @@ -233,14 +233,18 @@ func (s *SharedServerSuite) TestActivityPauseUnpause() { func (s *SharedServerSuite) TestActivityCommandFailed_NoActivityId() { run := s.waitActivityStarted() - // pause is single-workflow only + // pause is single-operation only; its error names --activity-id (and the + // optional --workflow-id/--run-id) but not --query. res := sendActivityCommand("pause", run, s) - s.ErrorContains(res.Err, "Activity Id must be specified") + s.ErrorContains(res.Err, "must specify --activity-id") + s.NotContains(res.Err.Error(), "--query") - // unpause and reset support both single-workflow and batch modes + // unpause and reset support both single-operation and batch modes, so their + // error names --activity-id and --query. for _, command := range []string{"unpause", "reset"} { res = sendActivityCommand(command, run, s) - s.ErrorContains(res.Err, "either --activity-id and --workflow-id, or --query must be set") + s.ErrorContains(res.Err, "must specify --activity-id") + s.ErrorContains(res.Err, "--query") } } @@ -279,6 +283,288 @@ func (s *SharedServerSuite) TestActivityReset() { s.ErrorAs(res.Err, ¬Found) } +// Standalone (workflow-less) activity tests. These exercise CLI routing to the +// *ActivityExecution APIs: when no --workflow-id is set, the activity is +// targeted by --activity-id and --run-id and the server routes the request to +// standalone-activity handling. + +func newStandaloneActivityID() string { + return "standalone-activity-" + uuid.NewString() +} + +func (s *SharedServerSuite) TestActivityStandalone_Pause() { + handle, stopFailing := s.startStandaloneActivity(newStandaloneActivityID()) + defer stopFailing() + + res := s.Execute( + "activity", "pause", + "--activity-id", handle.GetID(), + "--run-id", handle.GetRunID(), + "--identity", identity, + "--address", s.Address(), + ) + s.NoError(res.Err) + + s.Eventually(func() bool { + return s.standaloneActivityRunState(handle) == enums.PENDING_ACTIVITY_STATE_PAUSED + }, 10*time.Second, 100*time.Millisecond) +} + +func (s *SharedServerSuite) TestActivityStandalone_Unpause() { + handle, stopFailing := s.startStandaloneActivity(newStandaloneActivityID()) + defer stopFailing() + + res := s.Execute( + "activity", "pause", + "--activity-id", handle.GetID(), + "--run-id", handle.GetRunID(), + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Eventually(func() bool { + return s.standaloneActivityRunState(handle) == enums.PENDING_ACTIVITY_STATE_PAUSED + }, 10*time.Second, 100*time.Millisecond) + + res = s.Execute( + "activity", "unpause", + "--activity-id", handle.GetID(), + "--run-id", handle.GetRunID(), + "--reset-attempts", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Eventually(func() bool { + return s.standaloneActivityRunState(handle) != enums.PENDING_ACTIVITY_STATE_PAUSED + }, 10*time.Second, 100*time.Millisecond) +} + +func (s *SharedServerSuite) TestActivityStandalone_Reset() { + handle, stopFailing := s.startStandaloneActivity(newStandaloneActivityID()) + defer stopFailing() + + res := s.Execute( + "activity", "reset", + "--activity-id", handle.GetID(), + "--run-id", handle.GetRunID(), + "--address", s.Address(), + ) + s.NoError(res.Err) + s.ContainsOnSameLine(res.Stdout.String(), "ServerResponse", "true") + + // Targeting a missing standalone activity surfaces the server's NotFound. + res = s.Execute( + "activity", "reset", + "--activity-id", "fake-standalone-id", + "--run-id", handle.GetRunID(), + "--address", s.Address(), + ) + s.Error(res.Err) + var notFound *serviceerror.NotFound + s.ErrorAs(res.Err, ¬Found) +} + +func (s *SharedServerSuite) TestActivityStandalone_UpdateOptions() { + handle, stopFailing := s.startStandaloneActivity(newStandaloneActivityID()) + defer stopFailing() + + res := s.Execute( + "activity", "update-options", + "--activity-id", handle.GetID(), + "--run-id", handle.GetRunID(), + "--identity", identity, + "--schedule-to-close-timeout", "60s", + "--start-to-close-timeout", "10s", + "--retry-initial-interval", "5s", + "--retry-maximum-attempts", "5", + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + s.ContainsOnSameLine(out, "ScheduleToCloseTimeout", "1m0s") + s.ContainsOnSameLine(out, "StartToCloseTimeout", "10s") + s.ContainsOnSameLine(out, "InitialInterval", "5s") + s.ContainsOnSameLine(out, "MaximumAttempts", "5") +} + +func (s *SharedServerSuite) TestActivityStandalone_PauseByActivityIdOnly() { + handle, stopFailing := s.startStandaloneActivity(newStandaloneActivityID()) + defer stopFailing() + + // Without --run-id, the command targets the latest run of the Activity ID. + res := s.Execute( + "activity", "pause", + "--activity-id", handle.GetID(), + "--address", s.Address(), + ) + s.NoError(res.Err) + + s.Eventually(func() bool { + return s.standaloneActivityRunState(handle) == enums.PENDING_ACTIVITY_STATE_PAUSED + }, 10*time.Second, 100*time.Millisecond) +} + +func (s *SharedServerSuite) TestActivityStandalone_RequiresActivityId() { + // With neither --activity-id nor --query, every operation is an error, and + // the message tells the user how to retarget: it names --activity-id and the + // optional --workflow-id/--run-id, plus --query for the batch-capable + // operations (pause has no --query mode). + for _, command := range []string{"pause", "unpause", "reset", "update-options"} { + res := s.Execute( + "activity", command, + "--address", s.Address(), + ) + s.Error(res.Err, "command %q should require --activity-id", command) + s.ErrorContains(res.Err, "--activity-id") + s.ErrorContains(res.Err, "--workflow-id") + s.ErrorContains(res.Err, "--run-id") + if command == "pause" { + s.NotContains(res.Err.Error(), "--query") + } else { + s.ErrorContains(res.Err, "--query") + } + } +} + +// startStandaloneActivity starts a standalone (workflow-less) activity that +// fails and retries indefinitely, so it stays pending and can be paused, reset, +// or updated cleanly. It waits for the activity to be picked up and returns the +// handle plus a function that lets the activity complete (used for cleanup). +func (s *SharedServerSuite) startStandaloneActivity(actID string) (client.ActivityHandle, func()) { + var failActivity atomic.Bool + failActivity.Store(true) + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + if failActivity.Load() { + return nil, fmt.Errorf("standalone activity failing on purpose") + } + return nil, nil + }) + handle, err := s.Client.ExecuteActivity( + s.Context, + client.StartActivityOptions{ + ID: actID, + TaskQueue: s.Worker().Options.TaskQueue, + StartToCloseTimeout: time.Minute, + RetryPolicy: &temporal.RetryPolicy{ + InitialInterval: time.Second, + MaximumInterval: time.Second, + }, + }, + "DevActivity", + "input", + ) + s.NoError(err) + s.Eventually(func() bool { + desc, err := handle.Describe(s.Context, client.DescribeActivityOptions{}) + s.NoError(err) + return desc.Attempt >= 1 + }, 10*time.Second, 100*time.Millisecond) + return handle, func() { failActivity.Store(false) } +} + +func (s *SharedServerSuite) standaloneActivityRunState(handle client.ActivityHandle) enums.PendingActivityState { + desc, err := handle.Describe(s.Context, client.DescribeActivityOptions{}) + s.NoError(err) + return desc.RunState +} + +// TestActivityInvalidTargeting covers every invalid row of the activity +// single-operation targeting matrix, across all of the operations that share +// it. A single operation needs --activity-id plus either --workflow-id or +// --run-id, and --query is mutually exclusive with both --workflow-id and +// --run-id, so each of these combinations is rejected. +// +// reset/unpause/update-options reject the --query combinations as targeting +// errors. pause has no --query flag, so it rejects them as unknown-flag errors; +// either way the combination is rejected, which is the behavior under test. +func (s *SharedServerSuite) TestActivityInvalidTargeting() { + const q = "WorkflowType='DevWorkflow'" + cases := []struct { + name string + activityID string + workflowID string + runID string + query string + }{ + {name: "nothing set"}, + {name: "run-id only", runID: "r-id"}, + {name: "run-id and query", runID: "r-id", query: q}, + {name: "workflow-id only", workflowID: "w-id"}, + {name: "workflow-id and query", workflowID: "w-id", query: q}, + {name: "workflow-id and run-id, no activity-id", workflowID: "w-id", runID: "r-id"}, + {name: "workflow-id, run-id, and query", workflowID: "w-id", runID: "r-id", query: q}, + {name: "activity-id, run-id, and query", activityID: "a-id", runID: "r-id", query: q}, + {name: "activity-id, workflow-id, and query", activityID: "a-id", workflowID: "w-id", query: q}, + {name: "all flags set", activityID: "a-id", workflowID: "w-id", runID: "r-id", query: q}, + } + for _, command := range []string{"pause", "unpause", "reset", "update-options"} { + for _, tc := range cases { + args := []string{"activity", command, "--address", s.Address()} + if tc.activityID != "" { + args = append(args, "--activity-id", tc.activityID) + } + if tc.workflowID != "" { + args = append(args, "--workflow-id", tc.workflowID) + } + if tc.runID != "" { + args = append(args, "--run-id", tc.runID) + } + if tc.query != "" { + args = append(args, "--query", tc.query) + } + res := s.Execute(args...) + s.Error(res.Err, "command %q case %q should be invalid", command, tc.name) + } + } +} + +// TestActivityReset_WorkflowActivityLatestRun covers --activity-id + +// --workflow-id with no --run-id: a specific activity in the workflow's latest +// run. +func (s *SharedServerSuite) TestActivityReset_WorkflowActivityLatestRun() { + run := s.waitActivityStarted() + + res := s.Execute( + "activity", "reset", + "--activity-id", activityId, + "--workflow-id", run.GetID(), + "--address", s.Address(), + ) + s.NoError(res.Err) + s.ContainsOnSameLine(res.Stdout.String(), "ServerResponse", "true") +} + +// TestActivityReset_ActivityIdWithQueryStartsBatch covers --activity-id + +// --query: the activity ID is ignored and a batch over the matching workflows +// is started instead. +func (s *SharedServerSuite) TestActivityReset_ActivityIdWithQueryStartsBatch() { + run := s.waitActivityStarted() + + var startedBatch atomic.Bool + 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 _, ok := req.(*workflowservice.StartBatchOperationRequest); ok { + startedBatch.Store(true) + } + return invoker(ctx, method, req, reply, cc, opts...) + }), + ) + + res := s.Execute( + "activity", "reset", + "--activity-id", "ignored-activity-id", + "--query", fmt.Sprintf("WorkflowId = '%s'", run.GetID()), + "--yes", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.True(startedBatch.Load(), "a batch operation should have been started") +} + // Test helpers func (s *SharedServerSuite) waitActivityStarted() client.WorkflowRun { diff --git a/internal/temporalcli/commands.gen.go b/internal/temporalcli/commands.gen.go index 42c17e7d4..77af3dd9d 100644 --- a/internal/temporalcli/commands.gen.go +++ b/internal/temporalcli/commands.gen.go @@ -536,7 +536,11 @@ func NewTemporalActivityCommand(cctx *CommandContext, parent *TemporalCommand) * s.Parent = parent s.Command.Use = "activity" s.Command.Short = "Operate on Activity Executions" - s.Command.Long = "Perform operations on Activity Executions." + if hasHighlighting { + s.Command.Long = "Perform operations on Activity Executions.\n\n\x1b[1mtemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 5m\x1b[0m" + } else { + s.Command.Long = "Perform operations on Activity Executions.\n\n```\ntemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 5m\n```" + } s.Command.Args = cobra.NoArgs s.Command.AddCommand(&NewTemporalActivityCancelCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityCompleteCommand(cctx, &s).Command) @@ -601,9 +605,9 @@ func NewTemporalActivityCompleteCommand(cctx *CommandContext, parent *TemporalAc s.Command.Use = "complete [flags]" s.Command.Short = "Mark an activity as completed successfully with a result" if hasHighlighting { - s.Command.Long = "Complete an Activity, marking it as successfully finished. Specify the\nActivity ID and include a JSON result for the returned value:\n\n\x1b[1mtemporal activity complete \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --result '{\"YourResultKey\": \"YourResultVal\"}'\x1b[0m" + s.Command.Long = "Complete an Activity, marking it as successfully finished. Specify the\nActivity ID and include a JSON result for the returned value:\n\n\x1b[1mtemporal activity complete \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --result '{\"YourResultKey\": \"YourResultVal\"}'\x1b[0m\n\nOmit \x1b[1m--workflow-id\x1b[0m to target a Standalone Activity by Activity ID\nand optional Run ID." } else { - s.Command.Long = "Complete an Activity, marking it as successfully finished. Specify the\nActivity ID and include a JSON result for the returned value:\n\n```\ntemporal activity complete \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --result '{\"YourResultKey\": \"YourResultVal\"}'\n```" + s.Command.Long = "Complete an Activity, marking it as successfully finished. Specify the\nActivity ID and include a JSON result for the returned value:\n\n```\ntemporal activity complete \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --result '{\"YourResultKey\": \"YourResultVal\"}'\n```\n\nOmit `--workflow-id` to target a Standalone Activity by Activity ID\nand optional Run ID." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "Activity ID. This may be the ID of an Activity invoked by a Workflow, or of a Standalone Activity. Required.") @@ -661,9 +665,9 @@ func NewTemporalActivityDescribeCommand(cctx *CommandContext, parent *TemporalAc s.Command.Use = "describe [flags]" s.Command.Short = "Show detailed info for a Standalone Activity (Experimental)" if hasHighlighting { - s.Command.Long = "Display information about a Standalone Activity.\n\n\x1b[1mtemporal activity describe \\\n --activity-id YourActivityId\x1b[0m" + s.Command.Long = "Display information about a Standalone Activity.\n\n\x1b[1mtemporal activity describe \\\n --activity-id YourActivityId\x1b[0m\n\nIf \x1b[1m--run-id\x1b[0m is omitted, the latest Activity run is described." } else { - s.Command.Long = "Display information about a Standalone Activity.\n\n```\ntemporal activity describe \\\n --activity-id YourActivityId\n```" + s.Command.Long = "Display information about a Standalone Activity.\n\n```\ntemporal activity describe \\\n --activity-id YourActivityId\n```\n\nIf `--run-id` is omitted, the latest Activity run is described." } s.Command.Args = cobra.NoArgs s.Command.Flags().BoolVar(&s.Raw, "raw", false, "Print properties without changing their format.") @@ -690,9 +694,9 @@ func NewTemporalActivityExecuteCommand(cctx *CommandContext, parent *TemporalAct s.Command.Use = "execute [flags]" s.Command.Short = "Start a new Standalone Activity and wait for its result (Experimental)" if hasHighlighting { - s.Command.Long = "Start a new Standalone Activity and block until it completes.\nThe result is output to stdout.\n\n\x1b[1mtemporal activity execute \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 30s \\\n --input '{\"some-key\": \"some-value\"}'\x1b[0m" + s.Command.Long = "Start a new Standalone Activity and block until it completes.\nThe result is output to stdout.\n\n\x1b[1mtemporal activity execute \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 30s \\\n --input '{\"some-key\": \"some-value\"}'\x1b[0m\n\nThe command exits after the Activity completes." } else { - s.Command.Long = "Start a new Standalone Activity and block until it completes.\nThe result is output to stdout.\n\n```\ntemporal activity execute \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 30s \\\n --input '{\"some-key\": \"some-value\"}'\n```" + s.Command.Long = "Start a new Standalone Activity and block until it completes.\nThe result is output to stdout.\n\n```\ntemporal activity execute \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 30s \\\n --input '{\"some-key\": \"some-value\"}'\n```\n\nThe command exits after the Activity completes." } s.Command.Args = cobra.NoArgs s.ActivityStartOptions.BuildFlags(s.Command.Flags()) @@ -722,9 +726,9 @@ func NewTemporalActivityFailCommand(cctx *CommandContext, parent *TemporalActivi s.Command.Use = "fail [flags]" s.Command.Short = "Mark an Activity as completed unsuccessfully with an error" if hasHighlighting { - s.Command.Long = "Fail an Activity, marking it as having encountered an error:\n\n\x1b[1mtemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m" + s.Command.Long = "Fail an Activity, marking it as having encountered an error:\n\n\x1b[1mtemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m\n\nOmit \x1b[1m--workflow-id\x1b[0m to target a Standalone Activity by Activity ID\nand optional Run ID." } else { - s.Command.Long = "Fail an Activity, marking it as having encountered an error:\n\n```\ntemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```" + s.Command.Long = "Fail an Activity, marking it as having encountered an error:\n\n```\ntemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```\n\nOmit `--workflow-id` to target a Standalone Activity by Activity ID\nand optional Run ID." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "Activity ID. This may be the ID of an Activity invoked by a Workflow, or of a Standalone Activity. Required.") @@ -773,10 +777,11 @@ func NewTemporalActivityListCommand(cctx *CommandContext, parent *TemporalActivi } type TemporalActivityPauseCommand struct { - Parent *TemporalActivityCommand - Command cobra.Command - WorkflowReferenceOptions + Parent *TemporalActivityCommand + Command cobra.Command ActivityId string + WorkflowId string + RunId string Identity string Reason string } @@ -788,15 +793,16 @@ func NewTemporalActivityPauseCommand(cctx *CommandContext, parent *TemporalActiv s.Command.Use = "pause [flags]" s.Command.Short = "Pause an Activity" if hasHighlighting { - s.Command.Long = "Pause an Activity. Not supported for Standalone Activities.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nSpecify the Activity and Workflow IDs:\n\n\x1b[1mtemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." + s.Command.Long = "Pause an Activity.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nTo target a workflow Activity, specify the Activity and Workflow IDs:\n\n\x1b[1mtemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m\n\nTo target a standalone Activity, specify the Activity and Run IDs:\n\n\x1b[1mtemporal activity pause \\\n --activity-id YourActivityId \\\n --run-id YourRunId\x1b[0m\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." } else { - s.Command.Long = "Pause an Activity. Not supported for Standalone Activities.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nSpecify the Activity and Workflow IDs:\n\n```\ntemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." + s.Command.Long = "Pause an Activity.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nTo target a workflow Activity, specify the Activity and Workflow IDs:\n\n```\ntemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```\n\nTo target a standalone Activity, specify the Activity and Run IDs:\n\n```\ntemporal activity pause \\\n --activity-id YourActivityId \\\n --run-id YourRunId\n```\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to pause. Required.") + s.Command.Flags().StringVarP(&s.WorkflowId, "workflow-id", "w", "", "Workflow ID. Set to target a workflow Activity. Omit to target a standalone Activity.") + s.Command.Flags().StringVarP(&s.RunId, "run-id", "r", "", "Run ID. With --workflow-id, identifies the workflow run. For a standalone Activity (no --workflow-id), targets a specific run; omit to target the latest run.") s.Command.Flags().StringVar(&s.Identity, "identity", "", "The identity of the user or client submitting this request.") s.Command.Flags().StringVar(&s.Reason, "reason", "", "Reason for pausing the Activity.") - s.WorkflowReferenceOptions.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) @@ -824,12 +830,12 @@ func NewTemporalActivityResetCommand(cctx *CommandContext, parent *TemporalActiv s.Command.Use = "reset [flags]" s.Command.Short = "Reset an Activity" if hasHighlighting { - s.Command.Long = "Reset an activity. Not supported for Standalone Activities.\nThis restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify \x1b[1mkeep_paused\x1b[0m to prevent this.\n\nIf the activity is paused and the \x1b[1mkeep_paused\x1b[0m flag is not provided,\nit will be unpaused. If the activity is paused and \x1b[1mkeep_paused\x1b[0m flag\nis provided - it will stay paused.\n\nEither \x1b[1m--activity-id\x1b[0m (with \x1b[1m--workflow-id\x1b[0m) or \x1b[1m--query\x1b[0m must be specified.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a Canceled failure\nthe next time they heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the \x1b[1mreset_heartbeats\x1b[0m flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity and Workflow IDs:\n\n\x1b[1mtemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --keep-paused\n --reset-heartbeats\x1b[0m\n\nActivities can be reset in bulk with a visibility query list filter:\n\n\x1b[1mtemporal activity reset \\\n --query 'WorkflowType=\"YourWorkflow\"'\x1b[0m" + s.Command.Long = "Reset an activity.\nThis restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify \x1b[1m--keep-paused\x1b[0m to prevent this.\n\nIf the activity is paused and the \x1b[1m--keep-paused\x1b[0m flag is not provided,\nit will be unpaused. If the activity is paused and the \x1b[1m--keep-paused\x1b[0m\nflag is provided, it will stay paused.\n\nEither \x1b[1m--activity-id\x1b[0m (with \x1b[1m--workflow-id\x1b[0m for a workflow Activity, or\nalone for a standalone Activity) or \x1b[1m--query\x1b[0m must be specified.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a\nCanceled failure the next time\nthey heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the \x1b[1m--reset-heartbeats\x1b[0m flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity and Workflow IDs:\n\n\x1b[1mtemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --keep-paused \\\n --reset-heartbeats\x1b[0m\n\nActivities can be reset in bulk with a visibility query list filter:\n\n\x1b[1mtemporal activity reset \\\n --query 'WorkflowType=\"YourWorkflow\"'\x1b[0m\n\nOmit \x1b[1m--workflow-id\x1b[0m to target a Standalone Activity by Activity ID\nand optional Run ID." } else { - s.Command.Long = "Reset an activity. Not supported for Standalone Activities.\nThis restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify `keep_paused` to prevent this.\n\nIf the activity is paused and the `keep_paused` flag is not provided,\nit will be unpaused. If the activity is paused and `keep_paused` flag\nis provided - it will stay paused.\n\nEither `--activity-id` (with `--workflow-id`) or `--query` must be specified.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a Canceled failure\nthe next time they heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the `reset_heartbeats` flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity and Workflow IDs:\n\n```\ntemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --keep-paused\n --reset-heartbeats\n```\n\nActivities can be reset in bulk with a visibility query list filter:\n\n```\ntemporal activity reset \\\n --query 'WorkflowType=\"YourWorkflow\"'\n```" + s.Command.Long = "Reset an activity.\nThis restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify `--keep-paused` to prevent this.\n\nIf the activity is paused and the `--keep-paused` flag is not provided,\nit will be unpaused. If the activity is paused and the `--keep-paused`\nflag is provided, it will stay paused.\n\nEither `--activity-id` (with `--workflow-id` for a workflow Activity, or\nalone for a standalone Activity) or `--query` must be specified.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a\nCanceled failure the next time\nthey heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the `--reset-heartbeats` flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity and Workflow IDs:\n\n```\ntemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --keep-paused \\\n --reset-heartbeats\n```\n\nActivities can be reset in bulk with a visibility query list filter:\n\n```\ntemporal activity reset \\\n --query 'WorkflowType=\"YourWorkflow\"'\n```\n\nOmit `--workflow-id` to target a Standalone Activity by Activity ID\nand optional Run ID." } s.Command.Args = cobra.NoArgs - s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to reset. Mutually exclusive with `--query`. Requires `--workflow-id` to be specified.") + s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to reset. Mutually exclusive with `--query`. Set `--workflow-id` to target a workflow Activity, or omit it to target a standalone Activity (the latest run unless `--run-id` is set).") s.Command.Flags().BoolVar(&s.KeepPaused, "keep-paused", false, "If the activity was paused, it will stay paused.") s.Command.Flags().BoolVar(&s.ResetAttempts, "reset-attempts", false, "Reset the activity attempts.") s.Command.Flags().BoolVar(&s.ResetHeartbeats, "reset-heartbeats", false, "Reset the Activity's heartbeats.") @@ -858,9 +864,9 @@ func NewTemporalActivityResultCommand(cctx *CommandContext, parent *TemporalActi s.Command.Use = "result [flags]" s.Command.Short = "Wait for and output the result of a Standalone Activity (Experimental)" if hasHighlighting { - s.Command.Long = "Wait for a Standalone Activity to complete and output the\nresult.\n\n\x1b[1mtemporal activity result \\\n --activity-id YourActivityId\x1b[0m" + s.Command.Long = "Wait for a Standalone Activity to complete and output the\nresult.\n\n\x1b[1mtemporal activity result \\\n --activity-id YourActivityId\x1b[0m\n\nIf \x1b[1m--run-id\x1b[0m is omitted, the latest Activity run is used." } else { - s.Command.Long = "Wait for a Standalone Activity to complete and output the\nresult.\n\n```\ntemporal activity result \\\n --activity-id YourActivityId\n```" + s.Command.Long = "Wait for a Standalone Activity to complete and output the\nresult.\n\n```\ntemporal activity result \\\n --activity-id YourActivityId\n```\n\nIf `--run-id` is omitted, the latest Activity run is used." } s.Command.Args = cobra.NoArgs s.ActivityReferenceOptions.BuildFlags(s.Command.Flags()) @@ -886,9 +892,9 @@ func NewTemporalActivityStartCommand(cctx *CommandContext, parent *TemporalActiv s.Command.Use = "start [flags]" s.Command.Short = "Start a new Standalone Activity (Experimental)" if hasHighlighting { - s.Command.Long = "Start a new Standalone Activity. Outputs the Activity ID and\nRun ID.\n\n\x1b[1mtemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 5m \\\n --input '{\"some-key\": \"some-value\"}'\x1b[0m" + s.Command.Long = "Start a new Standalone Activity. Outputs the Activity ID and\nRun ID.\n\n\x1b[1mtemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 5m \\\n --input '{\"some-key\": \"some-value\"}'\x1b[0m\n\nThe command returns the Activity ID and Run ID." } else { - s.Command.Long = "Start a new Standalone Activity. Outputs the Activity ID and\nRun ID.\n\n```\ntemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 5m \\\n --input '{\"some-key\": \"some-value\"}'\n```" + s.Command.Long = "Start a new Standalone Activity. Outputs the Activity ID and\nRun ID.\n\n```\ntemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 5m \\\n --input '{\"some-key\": \"some-value\"}'\n```\n\nThe command returns the Activity ID and Run ID." } s.Command.Args = cobra.NoArgs s.ActivityStartOptions.BuildFlags(s.Command.Flags()) @@ -947,12 +953,12 @@ func NewTemporalActivityUnpauseCommand(cctx *CommandContext, parent *TemporalAct s.Command.Use = "unpause [flags]" s.Command.Short = "Unpause an Activity" if hasHighlighting { - s.Command.Long = "Re-schedule a previously-paused Activity for execution.\nNot supported for Standalone Activities.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse \x1b[1m--reset-attempts\x1b[0m to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, \x1b[1m--reset-attempts\x1b[0m will allow the\nActivity to be retried another N times after unpausing.\n\nUse \x1b[1m--reset-heartbeat\x1b[0m to reset the Activity's heartbeats.\n\nEither \x1b[1m--activity-id\x1b[0m (with \x1b[1m--workflow-id\x1b[0m) or \x1b[1m--query\x1b[0m must be specified.\n\nSpecify the Activity and Workflow IDs:\n\n\x1b[1mtemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --reset-attempts\n --reset-heartbeats\x1b[0m\n\nActivities can be unpaused in bulk via a visibility Query list filter:\n\n\x1b[1mtemporal activity unpause \\\n --query 'TemporalPauseInfo IS NOT NULL'\x1b[0m" + s.Command.Long = "Re-schedule a previously-paused Activity for execution.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse \x1b[1m--reset-attempts\x1b[0m to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, \x1b[1m--reset-attempts\x1b[0m will allow the\nActivity to be retried another N times after unpausing.\n\nUse \x1b[1m--reset-heartbeats\x1b[0m to reset the Activity's heartbeats.\n\nEither \x1b[1m--activity-id\x1b[0m (with \x1b[1m--workflow-id\x1b[0m for a workflow Activity, or\nalone for a standalone Activity) or \x1b[1m--query\x1b[0m must be specified.\n\nSpecify the Activity and Workflow IDs:\n\n\x1b[1mtemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --reset-attempts \\\n --reset-heartbeats\x1b[0m\n\nActivities can be unpaused in bulk via a visibility Query list filter:\n\n\x1b[1mtemporal activity unpause \\\n --query 'TemporalPauseInfo IS NOT NULL'\x1b[0m\n\nOmit \x1b[1m--workflow-id\x1b[0m to target a Standalone Activity by Activity ID\nand optional Run ID." } else { - s.Command.Long = "Re-schedule a previously-paused Activity for execution.\nNot supported for Standalone Activities.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse `--reset-attempts` to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, `--reset-attempts` will allow the\nActivity to be retried another N times after unpausing.\n\nUse `--reset-heartbeat` to reset the Activity's heartbeats.\n\nEither `--activity-id` (with `--workflow-id`) or `--query` must be specified.\n\nSpecify the Activity and Workflow IDs:\n\n```\ntemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --reset-attempts\n --reset-heartbeats\n```\n\nActivities can be unpaused in bulk via a visibility Query list filter:\n\n```\ntemporal activity unpause \\\n --query 'TemporalPauseInfo IS NOT NULL'\n```" + s.Command.Long = "Re-schedule a previously-paused Activity for execution.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse `--reset-attempts` to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, `--reset-attempts` will allow the\nActivity to be retried another N times after unpausing.\n\nUse `--reset-heartbeats` to reset the Activity's heartbeats.\n\nEither `--activity-id` (with `--workflow-id` for a workflow Activity, or\nalone for a standalone Activity) or `--query` must be specified.\n\nSpecify the Activity and Workflow IDs:\n\n```\ntemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --reset-attempts \\\n --reset-heartbeats\n```\n\nActivities can be unpaused in bulk via a visibility Query list filter:\n\n```\ntemporal activity unpause \\\n --query 'TemporalPauseInfo IS NOT NULL'\n```\n\nOmit `--workflow-id` to target a Standalone Activity by Activity ID\nand optional Run ID." } s.Command.Args = cobra.NoArgs - s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to unpause. Mutually exclusive with `--query`. Requires `--workflow-id` to be specified.") + s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to unpause. Mutually exclusive with `--query`. Set `--workflow-id` to target a workflow Activity, or omit it to target a standalone Activity (the latest run unless `--run-id` is set).") s.Command.Flags().BoolVar(&s.ResetAttempts, "reset-attempts", false, "Reset the activity attempts.") s.Command.Flags().BoolVar(&s.ResetHeartbeats, "reset-heartbeats", false, "Reset the Activity's heartbeats.") s.Jitter = 0 @@ -990,12 +996,12 @@ func NewTemporalActivityUpdateOptionsCommand(cctx *CommandContext, parent *Tempo s.Command.Use = "update-options [flags]" s.Command.Short = "Change the values of options affecting a running Activity" if hasHighlighting { - s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\nNot supported for Standalone Activities.\n\nFor example:\n\n\x1b[1mtemporal activity update-options \\\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\n\nYou may follow this command with \x1b[1mtemporal activity reset\x1b[0m, and the new values will apply after the reset.\n\nEither \x1b[1m--activity-id\x1b[0m or \x1b[1m--query\x1b[0m must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter:\n\n\x1b[1mtemporal activity update-options \\\n --query 'WorkflowType=\"YourWorkflow\"' \\\n --task-queue NewTaskQueueName\x1b[0m" + s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\n\nFor example:\n\n\x1b[1mtemporal activity update-options \\\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\n\nYou may follow this command with \x1b[1mtemporal activity reset\x1b[0m, and the new\nvalues will apply after the reset.\n\nEither \x1b[1m--activity-id\x1b[0m or \x1b[1m--query\x1b[0m must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter:\n\n\x1b[1mtemporal activity update-options \\\n --query 'WorkflowType=\"YourWorkflow\"' \\\n --task-queue NewTaskQueueName\x1b[0m\n\nOmit \x1b[1m--workflow-id\x1b[0m to target a Standalone Activity by Activity ID\nand optional Run ID." } else { - s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\nNot supported for Standalone Activities.\n\nFor example:\n\n```\ntemporal activity update-options \\\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\nYou may follow this command with `temporal activity reset`, and the new values will apply after the reset.\n\nEither `--activity-id` or `--query` must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter:\n\n```\ntemporal activity update-options \\\n --query 'WorkflowType=\"YourWorkflow\"' \\\n --task-queue NewTaskQueueName\n```" + s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\n\nFor example:\n\n```\ntemporal activity update-options \\\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\nYou may follow this command with `temporal activity reset`, and the new\nvalues will apply after the reset.\n\nEither `--activity-id` or `--query` must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter:\n\n```\ntemporal activity update-options \\\n --query 'WorkflowType=\"YourWorkflow\"' \\\n --task-queue NewTaskQueueName\n```\n\nOmit `--workflow-id` to target a Standalone Activity by Activity ID\nand optional Run ID." } s.Command.Args = cobra.NoArgs - s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to update options. Mutually exclusive with `--query`. Requires `--workflow-id` to be specified.") + s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to update options. Mutually exclusive with `--query`. Set `--workflow-id` to target a workflow Activity, or omit it to target a standalone Activity (the latest run unless `--run-id` is set).") 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.") diff --git a/internal/temporalcli/commands.yaml b/internal/temporalcli/commands.yaml index bc655419a..6c24431af 100644 --- a/internal/temporalcli/commands.yaml +++ b/internal/temporalcli/commands.yaml @@ -149,6 +149,14 @@ commands: summary: Operate on Activity Executions description: | Perform operations on Activity Executions. + + ``` + temporal activity start \ + --activity-id YourActivityId \ + --type YourActivity \ + --task-queue YourTaskQueue \ + --start-to-close-timeout 5m + ``` option-sets: - client docs: @@ -212,6 +220,9 @@ commands: --workflow-id YourWorkflowId \ --result '{"YourResultKey": "YourResultVal"}' ``` + + Omit `--workflow-id` to target a Standalone Activity by Activity ID + and optional Run ID. options: - name: activity-id short: a @@ -267,6 +278,8 @@ commands: temporal activity describe \ --activity-id YourActivityId ``` + + If `--run-id` is omitted, the latest Activity run is described. option-sets: - activity-reference options: @@ -288,6 +301,8 @@ commands: --start-to-close-timeout 30s \ --input '{"some-key": "some-value"}' ``` + + The command exits after the Activity completes. option-sets: - activity-start - payload-input @@ -302,6 +317,9 @@ commands: --activity-id YourActivityId \ --workflow-id YourWorkflowId ``` + + Omit `--workflow-id` to target a Standalone Activity by Activity ID + and optional Run ID. options: - name: activity-id short: a @@ -366,7 +384,6 @@ commands: description: | Update the options of a running Activity that were passed into it from a Workflow. Updates are incremental, only changing the specified options. - Not supported for Standalone Activities. For example: @@ -385,7 +402,8 @@ commands: --retry-maximum-attempts NewMaximumAttempts ``` - You may follow this command with `temporal activity reset`, and the new values will apply after the reset. + You may follow this command with `temporal activity reset`, and the new + values will apply after the reset. Either `--activity-id` or `--query` must be specified. @@ -396,12 +414,17 @@ commands: --query 'WorkflowType="YourWorkflow"' \ --task-queue NewTaskQueueName ``` + + Omit `--workflow-id` to target a Standalone Activity by Activity ID + and optional Run ID. options: - name: activity-id short: a type: string description: | - The Activity ID to update options. Mutually exclusive with `--query`. Requires `--workflow-id` to be specified. + The Activity ID to update options. Mutually exclusive with `--query`. + Set `--workflow-id` to target a workflow Activity, or omit it to target + a standalone Activity (the latest run unless `--run-id` is set). - name: task-queue type: string description: Name of the task queue for the Activity. @@ -463,7 +486,7 @@ commands: - name: temporal activity pause summary: Pause an Activity description: | - Pause an Activity. Not supported for Standalone Activities. + Pause an Activity. If the Activity is not currently running (e.g. because it previously failed), it will not be run again until it is unpaused. @@ -474,7 +497,7 @@ commands: If the Activity is on its last retry attempt and fails, the failure will be returned to the caller, just as if the Activity had not been paused. - Specify the Activity and Workflow IDs: + To target a workflow Activity, specify the Activity and Workflow IDs: ``` temporal activity pause \ @@ -482,6 +505,14 @@ commands: --workflow-id YourWorkflowId ``` + To target a standalone Activity, specify the Activity and Run IDs: + + ``` + temporal activity pause \ + --activity-id YourActivityId \ + --run-id YourRunId + ``` + To later unpause the activity, see [unpause](#unpause). You may also want to [reset](#reset) the activity to unpause it while also starting it from the beginning. options: @@ -489,20 +520,30 @@ commands: short: a type: string description: The Activity ID to pause. Required. + - name: workflow-id + short: w + type: string + description: | + Workflow ID. Set to target a workflow Activity. Omit to target a + standalone Activity. + - name: run-id + short: r + type: string + description: | + Run ID. With --workflow-id, identifies the workflow run. For a + standalone Activity (no --workflow-id), targets a specific run; + omit to target the latest run. - name: identity type: string description: The identity of the user or client submitting this request. - name: reason type: string description: Reason for pausing the Activity. - option-sets: - - workflow-reference - name: temporal activity unpause summary: Unpause an Activity description: | Re-schedule a previously-paused Activity for execution. - Not supported for Standalone Activities. If the Activity is not running and is past its retry timeout, it will be scheduled immediately. Otherwise, it will be scheduled after its retry @@ -513,17 +554,18 @@ commands: N specified in its retry policy, `--reset-attempts` will allow the Activity to be retried another N times after unpausing. - Use `--reset-heartbeat` to reset the Activity's heartbeats. + Use `--reset-heartbeats` to reset the Activity's heartbeats. - Either `--activity-id` (with `--workflow-id`) or `--query` must be specified. + Either `--activity-id` (with `--workflow-id` for a workflow Activity, or + alone for a standalone Activity) or `--query` must be specified. Specify the Activity and Workflow IDs: ``` temporal activity unpause \ --activity-id YourActivityId \ - --workflow-id YourWorkflowId - --reset-attempts + --workflow-id YourWorkflowId \ + --reset-attempts \ --reset-heartbeats ``` @@ -533,12 +575,17 @@ commands: temporal activity unpause \ --query 'TemporalPauseInfo IS NOT NULL' ``` + + Omit `--workflow-id` to target a Standalone Activity by Activity ID + and optional Run ID. options: - name: activity-id short: a type: string description: | - The Activity ID to unpause. Mutually exclusive with `--query`. Requires `--workflow-id` to be specified. + The Activity ID to unpause. Mutually exclusive with `--query`. + Set `--workflow-id` to target a workflow Activity, or omit it to target + a standalone Activity (the latest run unless `--run-id` is set). - name: reset-attempts type: bool description: Reset the activity attempts. @@ -556,7 +603,7 @@ commands: - name: temporal activity reset summary: Reset an Activity description: | - Reset an activity. Not supported for Standalone Activities. + Reset an activity. This restarts the activity as if it were first being scheduled. That is, it will reset both the number of attempts and the activity timeout, as well as, optionally, the @@ -568,31 +615,33 @@ commands: will apply immediately. If the activity is already paused, it will be unpaused by default. - You can specify `keep_paused` to prevent this. + You can specify `--keep-paused` to prevent this. - If the activity is paused and the `keep_paused` flag is not provided, - it will be unpaused. If the activity is paused and `keep_paused` flag - is provided - it will stay paused. + If the activity is paused and the `--keep-paused` flag is not provided, + it will be unpaused. If the activity is paused and the `--keep-paused` + flag is provided, it will stay paused. - Either `--activity-id` (with `--workflow-id`) or `--query` must be specified. + Either `--activity-id` (with `--workflow-id` for a workflow Activity, or + alone for a standalone Activity) or `--query` must be specified. ### Resetting activities that heartbeat {#reset-heartbeats} - Activities that heartbeat will receive a [Canceled failure](/references/failures#cancelled-failure) - the next time they heartbeat after a reset. + Activities that heartbeat will receive a + [Canceled failure](/references/failures#cancelled-failure) the next time + they heartbeat after a reset. If, in your Activity, you need to do any cleanup when an Activity is reset, handle this error and then re-throw it when you've cleaned up. - If the `reset_heartbeats` flag is set, the heartbeat details will also be cleared. + If the `--reset-heartbeats` flag is set, the heartbeat details will also be cleared. Specify the Activity and Workflow IDs: ``` temporal activity reset \ --activity-id YourActivityId \ - --workflow-id YourWorkflowId - --keep-paused + --workflow-id YourWorkflowId \ + --keep-paused \ --reset-heartbeats ``` @@ -602,11 +651,17 @@ commands: temporal activity reset \ --query 'WorkflowType="YourWorkflow"' ``` + + Omit `--workflow-id` to target a Standalone Activity by Activity ID + and optional Run ID. options: - name: activity-id short: a type: string - description: The Activity ID to reset. Mutually exclusive with `--query`. Requires `--workflow-id` to be specified. + description: | + The Activity ID to reset. Mutually exclusive with `--query`. + Set `--workflow-id` to target a workflow Activity, or omit it to target + a standalone Activity (the latest run unless `--run-id` is set). - name: keep-paused type: bool description: If the activity was paused, it will stay paused. @@ -638,6 +693,8 @@ commands: temporal activity result \ --activity-id YourActivityId ``` + + If `--run-id` is omitted, the latest Activity run is used. option-sets: - activity-reference @@ -655,6 +712,8 @@ commands: --start-to-close-timeout 5m \ --input '{"some-key": "some-value"}' ``` + + The command returns the Activity ID and Run ID. option-sets: - activity-start - payload-input