diff --git a/go.mod b/go.mod index 02ef784dd..704f97fe6 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/temporalio/cli/cliext v0.0.0 github.com/temporalio/ui-server/v2 v2.52.0 go.temporal.io/api v1.63.0 - go.temporal.io/sdk v1.44.1 + go.temporal.io/sdk v1.45.0 go.temporal.io/sdk/contrib/envconfig v1.0.2 go.temporal.io/server v1.32.0-158.0 golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f diff --git a/go.sum b/go.sum index 5f544e484..da4e8d5a5 100644 --- a/go.sum +++ b/go.sum @@ -475,8 +475,8 @@ go.temporal.io/api v1.63.0 h1:YZFOTA0/thRUIUC4qunAWdHhPh/IG4vy/+WjfEvT+ZE= go.temporal.io/api v1.63.0/go.mod h1:0k75tRljEuELWGeXjEZZO7zYqBln4+1FrG6+IMOMy7Q= go.temporal.io/auto-scaled-workers v0.0.0-20260622220320-9b1e3849116d h1:f7+FCJHSrYWz9zvJp2OxKo8Fu/dsBUdnZZA+m5CEOS0= go.temporal.io/auto-scaled-workers v0.0.0-20260622220320-9b1e3849116d/go.mod h1:HOnbQTZCW18EPcutFHTkZrDcGO4tUjQ8N2pjDyrGhrY= -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 v1.45.0 h1:kvsczo3SHTS60+zBWH9lljLmBLWSXcyGkBxr88z8iQI= +go.temporal.io/sdk v1.45.0/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-158.0 h1:M+rXAmFztzBrIXNYPZyUPJFZO6yHPKP1lRTrQNUKvbs= diff --git a/internal/temporalcli/commands.activity.go b/internal/temporalcli/commands.activity.go index 582f5d622..4b8fc6537 100644 --- a/internal/temporalcli/commands.activity.go +++ b/internal/temporalcli/commands.activity.go @@ -131,6 +131,7 @@ func buildStartActivityOptions(opts *ActivityStartOptions) (client.StartActivity ScheduleToStartTimeout: opts.ScheduleToStartTimeout.Duration(), StartToCloseTimeout: opts.StartToCloseTimeout.Duration(), HeartbeatTimeout: opts.HeartbeatTimeout.Duration(), + StartDelay: opts.StartDelay.Duration(), Summary: opts.StaticSummary, Details: opts.StaticDetails, Priority: temporal.Priority{ @@ -407,6 +408,7 @@ func printActivityDescription(cctx *CommandContext, info *activitypb.ActivityExe ScheduleToStartTimeout time.Duration `cli:",cardOmitEmpty"` StartToCloseTimeout time.Duration `cli:",cardOmitEmpty"` HeartbeatTimeout time.Duration `cli:",cardOmitEmpty"` + StartDelay time.Duration `cli:",cardOmitEmpty"` LastStartedTime time.Time `cli:",cardOmitEmpty"` Attempt int32 ExecutionDuration time.Duration `cli:",cardOmitEmpty"` @@ -427,6 +429,7 @@ func printActivityDescription(cctx *CommandContext, info *activitypb.ActivityExe ScheduleToStartTimeout: info.GetScheduleToStartTimeout().AsDuration(), StartToCloseTimeout: info.GetStartToCloseTimeout().AsDuration(), HeartbeatTimeout: info.GetHeartbeatTimeout().AsDuration(), + StartDelay: info.GetStartDelay().AsDuration(), LastStartedTime: timestampToTime(info.GetLastStartedTime()), Attempt: info.GetAttempt(), ExecutionDuration: info.GetExecutionDuration().AsDuration(), diff --git a/internal/temporalcli/commands.activity_test.go b/internal/temporalcli/commands.activity_test.go index ec6b50a4f..b195e22d3 100644 --- a/internal/temporalcli/commands.activity_test.go +++ b/internal/temporalcli/commands.activity_test.go @@ -607,6 +607,39 @@ func (s *SharedServerSuite) TestActivity_Start_With_Headers() { s.Equal(123, val) } +func (s *SharedServerSuite) TestActivity_Start_StartDelay() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return nil, nil + }) + + var capturedRequest *workflowservice.StartActivityExecutionRequest + 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 startReq, ok := req.(*workflowservice.StartActivityExecutionRequest); ok { + capturedRequest = startReq + } + return invoker(ctx, method, req, reply, cc, opts...) + }), + ) + + res := s.Execute( + "activity", "start", + "--activity-id", "start-delay-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--start-delay", "2s", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Equal(2*time.Second, capturedRequest.GetStartDelay().AsDuration()) +} + func (s *SharedServerSuite) TestActivity_Execute_Success() { var receivedInput any s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { @@ -902,6 +935,48 @@ func (s *SharedServerSuite) TestActivity_Describe() { s.Contains(rawOut, `{"name":"DevActivity"}`) } +func (s *SharedServerSuite) TestActivity_Describe_StartDelay() { + started := s.startActivity("describe-start-delay-test", "--start-delay", "2s") + runID := started["runId"].(string) + + // Text + res := s.Execute( + "activity", "describe", + "--activity-id", "describe-start-delay-test", + "--run-id", runID, + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + s.ContainsOnSameLine(out, "ActivityId", "describe-start-delay-test") + s.ContainsOnSameLine(out, "StartDelay", "2s") + + // JSON + res = s.Execute( + "activity", "describe", + "-o", "json", + "--activity-id", "describe-start-delay-test", + "--run-id", runID, + "--address", s.Address(), + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal("2s", jsonOut["startDelay"]) + + // Raw + res = s.Execute( + "activity", "describe", + "--raw", + "--activity-id", "describe-start-delay-test", + "--run-id", runID, + "--address", s.Address(), + ) + s.NoError(res.Err) + rawOut := res.Stdout.String() + s.ContainsOnSameLine(rawOut, "StartDelay", `"2s"`) +} + // Text-only: verifies LastFailure is rendered as text not JSON. func (s *SharedServerSuite) TestActivity_Describe_FailedLastFailure() { s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { diff --git a/internal/temporalcli/commands.gen.go b/internal/temporalcli/commands.gen.go index 6fcf8bb1a..56e0cfa25 100644 --- a/internal/temporalcli/commands.gen.go +++ b/internal/temporalcli/commands.gen.go @@ -443,6 +443,7 @@ type ActivityStartOptions struct { ScheduleToStartTimeout cliext.FlagDuration StartToCloseTimeout cliext.FlagDuration HeartbeatTimeout cliext.FlagDuration + StartDelay cliext.FlagDuration RetryInitialInterval cliext.FlagDuration RetryMaximumInterval cliext.FlagDuration RetryBackoffCoefficient float32 @@ -475,6 +476,8 @@ func (v *ActivityStartOptions) BuildFlags(f *pflag.FlagSet) { f.Var(&v.StartToCloseTimeout, "start-to-close-timeout", "Maximum time for a single Activity attempt. On expiry a new attempt may be scheduled if permitted by the retry policy and schedule-to-close timeout. Either this or \"schedule-to-close-timeout\" is required.") v.HeartbeatTimeout = 0 f.Var(&v.HeartbeatTimeout, "heartbeat-timeout", "Maximum time between successful Worker heartbeats. On expiry the current activity attempt fails.") + v.StartDelay = 0 + f.Var(&v.StartDelay, "start-delay", "Delay before dispatching the first Activity task. This delay is not applied to retry attempts.") v.RetryInitialInterval = 0 f.Var(&v.RetryInitialInterval, "retry-initial-interval", "Interval of the first retry. If \"retry-backoff-coefficient\" is 1.0, it is used for all retries.") v.RetryMaximumInterval = 0 diff --git a/internal/temporalcli/commands.yaml b/internal/temporalcli/commands.yaml index ac166de20..6e11c2b23 100644 --- a/internal/temporalcli/commands.yaml +++ b/internal/temporalcli/commands.yaml @@ -5454,6 +5454,11 @@ option-sets: description: | Maximum time between successful Worker heartbeats. On expiry the current activity attempt fails. + - name: start-delay + type: duration + description: | + Delay before dispatching the first Activity task. + This delay is not applied to retry attempts. - name: retry-initial-interval type: duration description: | diff --git a/internal/temporalcli/commands_test.go b/internal/temporalcli/commands_test.go index 1b1a18e51..10e46aa91 100644 --- a/internal/temporalcli/commands_test.go +++ b/internal/temporalcli/commands_test.go @@ -239,6 +239,7 @@ func (s *SharedServerSuite) SetupSuite() { // the __temporal_system endpoint from inside a workflow. "history.enableSignalWithStartFromWorkflow": true, "activity.enableStandalone": true, + "activity.startDelayEnabled": true, "activity.longPollTimeout": 2 * time.Second, "nexusoperation.enableStandalone": true, "history.enableChasmCallbacks": true,