Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 12 additions & 6 deletions internal/temporalcli/commands.workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -569,13 +569,19 @@ func (s *SingleWorkflowOrBatchOptions) workflowExecOrBatch(
return nil, nil, fmt.Errorf("cannot set run ID when query is set")
}

// Count the workflows that will be affected
count, err := cl.CountWorkflow(cctx, &workflowservice.CountWorkflowExecutionsRequest{Query: s.Query})
if err != nil {
return nil, nil, fmt.Errorf("failed counting workflows from query: %w", err)
// The count is only used in the confirmation prompt; skip the request when --yes
// bypasses it, so batch jobs can still proceed if the visibility API is timing out.
var promptMessage string
if s.Yes {
promptMessage = fmt.Sprintf("Start batch against workflows matching query %q? y/N", s.Query)
} else {
count, err := cl.CountWorkflow(cctx, &workflowservice.CountWorkflowExecutionsRequest{Query: s.Query})
if err != nil {
return nil, nil, fmt.Errorf("failed counting workflows from query: %w", err)
}
promptMessage = fmt.Sprintf("Start batch against approximately %v workflow(s)? y/N", count.Count)
}
yes, err := cctx.promptYes(
fmt.Sprintf("Start batch against approximately %v workflow(s)? y/N", count.Count), s.Yes)
yes, err := cctx.promptYes(promptMessage, s.Yes)
if err != nil {
return nil, nil, err
} else if !yes {
Expand Down
17 changes: 12 additions & 5 deletions internal/temporalcli/commands.workflow_reset.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,19 @@ func (c *TemporalWorkflowResetCommand) runBatchResetWithPostOps(cctx *CommandCon
PostResetOperations: postOps,
},
}
count, err := cl.CountWorkflow(cctx, &workflowservice.CountWorkflowExecutionsRequest{Query: c.Query})
if err != nil {
return fmt.Errorf("failed counting workflows from query: %w", err)
// The count is only used in the confirmation prompt; skip the request when --yes
// bypasses it, so batch jobs can still proceed if the visibility API is timing out.
var promptMessage string
if c.Yes {
promptMessage = fmt.Sprintf("Start batch against workflows matching query %q? y/N", c.Query)
} else {
count, err := cl.CountWorkflow(cctx, &workflowservice.CountWorkflowExecutionsRequest{Query: c.Query})
if err != nil {
return fmt.Errorf("failed counting workflows from query: %w", err)
}
promptMessage = fmt.Sprintf("Start batch against approximately %v workflow(s)? y/N", count.Count)
}
yes, err := cctx.promptYes(
fmt.Sprintf("Start batch against approximately %v workflow(s)? y/N", count.Count), c.Yes)
yes, err := cctx.promptYes(promptMessage, c.Yes)
if err != nil {
return err
}
Expand Down
39 changes: 39 additions & 0 deletions internal/temporalcli/commands.workflow_reset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -927,3 +927,42 @@ func (sut *batchResetTestData) getWorkflowHistory() ([]*history.HistoryEvent, er

return events, nil
}

func (s *SharedServerSuite) TestWorkflow_ResetBatch_SkipsCountWhenYes() {
s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) {
ctx.Done().Receive(ctx, nil)
return nil, ctx.Err()
})

searchAttr := "keyword-" + uuid.NewString()
_, err := s.Client.ExecuteWorkflow(
s.Context,
client.StartWorkflowOptions{
TaskQueue: s.Worker().Options.TaskQueue,
SearchAttributes: map[string]any{"CustomKeywordField": searchAttr},
},
DevWorkflow,
"ignored",
)
s.NoError(err)
s.Eventually(func() bool {
resp, err := s.Client.ListWorkflow(s.Context, &workflowservice.ListWorkflowExecutionsRequest{
Query: "CustomKeywordField = '" + searchAttr + "'",
})
s.NoError(err)
return len(resp.Executions) == 1
}, 3*time.Second, 100*time.Millisecond)

res := s.Execute(
"workflow", "reset",
"--address", s.Address(),
"--query", "CustomKeywordField = '"+searchAttr+"'",
"--type", "FirstWorkflowTask",
"--reason", "skip-count-test",
"--yes",
)
s.NoError(res.Err)

s.NotContains(res.Stdout.String(), "approximately")
s.Contains(res.Stdout.String(), "matching query")
}
48 changes: 47 additions & 1 deletion internal/temporalcli/commands.workflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"regexp"
"strconv"
"strings"
"sync"
"time"

Expand Down Expand Up @@ -250,7 +251,7 @@ func (s *SharedServerSuite) TestWorkflow_Delete_BatchWorkflowSuccess() {
"-y",
)
s.NoError(res.Err)
s.Contains(res.Stdout.String(), "Start batch against approximately 2 workflow(s)")
s.Contains(res.Stdout.String(), "Start batch against workflows matching query")
s.NotContains(res.Stdout.String(), "Deleting Workflow Executions in a global Namespace")
s.NotContains(res.Stderr.String(), "Deleting Workflow Executions in a global Namespace")

Expand Down Expand Up @@ -387,6 +388,51 @@ func (s *SharedServerSuite) TestWorkflow_Terminate_BatchWorkflowSuccess_JSON() {
s.NotEmpty(jsonRes["batchJobId"])
}

func (s *SharedServerSuite) TestWorkflow_Terminate_BatchWorkflow_SkipsCountWhenYes() {
s.Worker().OnDevWorkflow(func(ctx workflow.Context, a any) (any, error) {
ctx.Done().Receive(ctx, nil)
return nil, ctx.Err()
})

searchAttr := "keyword-" + uuid.NewString()
run, err := s.Client.ExecuteWorkflow(
s.Context,
client.StartWorkflowOptions{
TaskQueue: s.Worker().Options.TaskQueue,
SearchAttributes: map[string]any{"CustomKeywordField": searchAttr},
},
DevWorkflow,
"ignored",
)
s.NoError(err)
s.Eventually(func() bool {
resp, err := s.Client.ListWorkflow(s.Context, &workflowservice.ListWorkflowExecutionsRequest{
Query: "CustomKeywordField = '" + searchAttr + "'",
})
s.NoError(err)
return len(resp.Executions) == 1
}, 3*time.Second, 100*time.Millisecond)

res := s.Execute(
"workflow", "terminate",
"--address", s.Address(),
"--query", "CustomKeywordField = '"+searchAttr+"'",
"--reason", "skip-count-test",
"--yes",
)
s.NoError(res.Err)

// Prompt text should show the query, not the count
s.NotContains(res.Stdout.String(), "approximately")
s.Contains(res.Stdout.String(), "matching query")

// Confirm workflow was terminated
s.Eventually(func() bool {
err := run.Get(s.Context, nil)
return err != nil && strings.Contains(err.Error(), "terminated")
}, 5*time.Second, 100*time.Millisecond)
}

func (s *SharedServerSuite) testTerminateBatchWorkflow(
total int,
rps float32,
Expand Down
Loading