diff --git a/internal/temporalcli/commands.gen.go b/internal/temporalcli/commands.gen.go index ca95a64b2..ee980cf6e 100644 --- a/internal/temporalcli/commands.gen.go +++ b/internal/temporalcli/commands.gen.go @@ -3570,6 +3570,7 @@ func NewTemporalWorkerCommand(cctx *CommandContext, parent *TemporalCommand) *Te s.Command.Long = "Modify or read state associated with a Worker, for example,\nusing Worker Deployments commands:\n\n```\ntemporal worker deployment\n```" } s.Command.Args = cobra.NoArgs + s.Command.AddCommand(&NewTemporalWorkerCountCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalWorkerDeploymentCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalWorkerDescribeCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalWorkerListCommand(cctx, &s).Command) @@ -3577,6 +3578,35 @@ func NewTemporalWorkerCommand(cctx *CommandContext, parent *TemporalCommand) *Te return &s } +type TemporalWorkerCountCommand struct { + Parent *TemporalWorkerCommand + Command cobra.Command + Query string + IncludeSystemWorkers bool +} + +func NewTemporalWorkerCountCommand(cctx *CommandContext, parent *TemporalWorkerCommand) *TemporalWorkerCountCommand { + var s TemporalWorkerCountCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "count [flags]" + s.Command.Short = "Count workers in a namespace (EXPERIMENTAL)" + if hasHighlighting { + s.Command.Long = "Show a count of workers in a namespace. Use \x1b[1m--query\x1b[0m to count a subset:\n\n\x1b[1mtemporal worker count --namespace YourNamespace --query 'TaskQueue=\"YourTaskQueue\"'\x1b[0m" + } else { + s.Command.Long = "Show a count of workers in a namespace. Use `--query` to count a subset:\n\n```\ntemporal worker count --namespace YourNamespace --query 'TaskQueue=\"YourTaskQueue\"'\n```" + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVarP(&s.Query, "query", "q", "", "Content for an SQL-like `QUERY` List Filter.") + s.Command.Flags().BoolVar(&s.IncludeSystemWorkers, "include-system-workers", false, "Include system workers created by the server.") + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + type TemporalWorkerDeploymentCommand struct { Parent *TemporalWorkerCommand Command cobra.Command diff --git a/internal/temporalcli/commands.worker.go b/internal/temporalcli/commands.worker.go index ce737da11..574a5d1ea 100644 --- a/internal/temporalcli/commands.worker.go +++ b/internal/temporalcli/commands.worker.go @@ -84,6 +84,30 @@ type workerDescribeDetail struct { Plugins []pluginInfo `cli:",cardOmitEmpty"` } +func (c *TemporalWorkerCountCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + resp, err := cl.WorkflowService().CountWorkers(cctx, &workflowservice.CountWorkersRequest{ + Namespace: c.Parent.Namespace, + Query: c.Query, + IncludeSystemWorkers: c.IncludeSystemWorkers, + }) + if err != nil { + return err + } + + if cctx.JSONOutput { + return cctx.Printer.PrintStructured(resp, printer.StructuredOptions{}) + } + + cctx.Printer.Printlnf("%v", resp.Count) + return nil +} + func (c *TemporalWorkerDescribeCommand) run(cctx *CommandContext, args []string) error { cl, err := dialClient(cctx, &c.Parent.ClientOptions) if err != nil { diff --git a/internal/temporalcli/commands.worker_test.go b/internal/temporalcli/commands.worker_test.go index 3c52eb272..7c1b1ecc5 100644 --- a/internal/temporalcli/commands.worker_test.go +++ b/internal/temporalcli/commands.worker_test.go @@ -64,6 +64,38 @@ func (s *SharedServerSuite) TestWorkerHeartbeat_List() { s.ContainsOnSameLine(res.Stdout.String(), heartbeat.WorkerInstanceKey, heartbeat.TaskQueue, heartbeat.WorkerIdentity) } +func (s *SharedServerSuite) TestWorkerCount() { + heartbeat, err := s.recordWorkerHeartbeat() + s.NoError(err) + + // Wait for worker to be visible + s.waitForWorkerListJSON(heartbeat.TaskQueue, heartbeat.WorkerInstanceKey) + + // Count with query filter + res := s.Execute( + "worker", "count", + "--address", s.Address(), + "--query", fmt.Sprintf("TaskQueue=\"%s\"", heartbeat.TaskQueue), + ) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "1") + + // JSON output + res = s.Execute( + "worker", "count", + "--address", s.Address(), + "--query", fmt.Sprintf("TaskQueue=\"%s\"", heartbeat.TaskQueue), + "--output", "json", + ) + s.NoError(res.Err) + + var parsed struct { + Count json.Number `json:"count"` + } + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &parsed)) + s.Equal("1", parsed.Count.String()) +} + func (s *SharedServerSuite) TestWorkerHeartbeat_List_IncludeSystemWorkers() { var lastRequestLock sync.Mutex var listWorkersRequest *workflowservice.ListWorkersRequest diff --git a/internal/temporalcli/commands.yaml b/internal/temporalcli/commands.yaml index 542ded558..b3e40397c 100644 --- a/internal/temporalcli/commands.yaml +++ b/internal/temporalcli/commands.yaml @@ -1706,6 +1706,23 @@ commands: type: bool description: Include system workers that are created implicitly by the server. By default, system workers are excluded. + - name: temporal worker count + summary: Count workers in a namespace (EXPERIMENTAL) + description: | + Show a count of workers in a namespace. Use `--query` to count a subset: + + ``` + temporal worker count --namespace YourNamespace --query 'TaskQueue="YourTaskQueue"' + ``` + options: + - name: query + short: q + type: string + description: Content for an SQL-like `QUERY` List Filter. + - name: include-system-workers + type: bool + description: Include system workers created by the server. + - name: temporal worker describe summary: Returns information about a specific worker (EXPERIMENTAL) description: |