From 2ebc1086613812613a078338af5e6feb9f56af9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D7=A0=CF=85=CE=B1=CE=B7=20=D7=A0=CF=85=CE=B1=CE=B7=D1=95?= =?UTF-8?q?=CF=83=CE=B7?= Date: Sat, 7 Mar 2026 11:17:44 -0800 Subject: [PATCH] feat(job): add status counts to job list, drop operation counts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add StatusCounts to ListJobsResponse and JobList so callers get per-status totals alongside paginated results. Remove the unused OperationCounts field from QueueStats and the API spec. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- docs/gen/gen.md | 48 ++++++++++++++++++------------------- docs/gen/osapi.md | 16 ++++++------- pkg/osapi/gen/api.yaml | 13 ++++++---- pkg/osapi/gen/client.gen.go | 6 ++--- pkg/osapi/job_types.go | 20 ++++++++-------- pkg/osapi/job_types_test.go | 30 +++++++++++------------ 6 files changed, 68 insertions(+), 65 deletions(-) diff --git a/docs/gen/gen.md b/docs/gen/gen.md index 4ed014b..6f6e60a 100644 --- a/docs/gen/gen.md +++ b/docs/gen/gen.md @@ -4008,7 +4008,7 @@ type ListAuditResponse struct { ``` -## type [ListJobsResponse]() +## type [ListJobsResponse]() ListJobsResponse defines model for ListJobsResponse. @@ -4016,13 +4016,16 @@ ListJobsResponse defines model for ListJobsResponse. type ListJobsResponse struct { Items *[]JobDetailResponse `json:"items,omitempty"` + // StatusCounts Count of all jobs by status (submitted, processing, completed, failed, partial_failure). Derived from key names during the listing pass — no extra reads. + StatusCounts *map[string]int `json:"status_counts,omitempty"` + // TotalItems Total number of jobs matching the filter. TotalItems *int `json:"total_items,omitempty"` } ``` -## type [LoadAverageResponse]() +## type [LoadAverageResponse]() LoadAverageResponse The system load averages for 1, 5, and 15 minutes. @@ -4040,7 +4043,7 @@ type LoadAverageResponse struct { ``` -## type [LoadCollectionResponse]() +## type [LoadCollectionResponse]() LoadCollectionResponse defines model for LoadCollectionResponse. @@ -4053,7 +4056,7 @@ type LoadCollectionResponse struct { ``` -## type [LoadResultItem]() +## type [LoadResultItem]() LoadResultItem defines model for LoadResultItem. @@ -4071,7 +4074,7 @@ type LoadResultItem struct { ``` -## type [MemoryCollectionResponse]() +## type [MemoryCollectionResponse]() MemoryCollectionResponse defines model for MemoryCollectionResponse. @@ -4084,7 +4087,7 @@ type MemoryCollectionResponse struct { ``` -## type [MemoryResponse]() +## type [MemoryResponse]() MemoryResponse Memory usage information. @@ -4102,7 +4105,7 @@ type MemoryResponse struct { ``` -## type [MemoryResultItem]() +## type [MemoryResultItem]() MemoryResultItem defines model for MemoryResultItem. @@ -4120,7 +4123,7 @@ type MemoryResultItem struct { ``` -## type [NATSInfo]() +## type [NATSInfo]() NATSInfo defines model for NATSInfo. @@ -4135,7 +4138,7 @@ type NATSInfo struct { ``` -## type [NetworkInterfaceResponse]() +## type [NetworkInterfaceResponse]() NetworkInterfaceResponse defines model for NetworkInterfaceResponse. @@ -4151,7 +4154,7 @@ type NetworkInterfaceResponse struct { ``` -## type [NetworkInterfaceResponseFamily]() +## type [NetworkInterfaceResponseFamily]() NetworkInterfaceResponseFamily IP address family. @@ -4170,7 +4173,7 @@ const ( ``` -## type [NodeCondition]() +## type [NodeCondition]() NodeCondition defines model for NodeCondition. @@ -4184,7 +4187,7 @@ type NodeCondition struct { ``` -## type [NodeConditionType]() +## type [NodeConditionType]() NodeConditionType defines model for NodeCondition.Type. @@ -4203,7 +4206,7 @@ const ( ``` -## type [NodeStatusCollectionResponse]() +## type [NodeStatusCollectionResponse]() NodeStatusCollectionResponse defines model for NodeStatusCollectionResponse. @@ -4216,7 +4219,7 @@ type NodeStatusCollectionResponse struct { ``` -## type [NodeStatusResponse]() +## type [NodeStatusResponse]() NodeStatusResponse defines model for NodeStatusResponse. @@ -4246,7 +4249,7 @@ type NodeStatusResponse struct { ``` -## type [OSInfoCollectionResponse]() +## type [OSInfoCollectionResponse]() OSInfoCollectionResponse defines model for OSInfoCollectionResponse. @@ -4259,7 +4262,7 @@ type OSInfoCollectionResponse struct { ``` -## type [OSInfoResponse]() +## type [OSInfoResponse]() OSInfoResponse Operating system information. @@ -4274,7 +4277,7 @@ type OSInfoResponse struct { ``` -## type [OSInfoResultItem]() +## type [OSInfoResultItem]() OSInfoResultItem defines model for OSInfoResultItem. @@ -4292,7 +4295,7 @@ type OSInfoResultItem struct { ``` -## type [ObjectStoreInfo]() +## type [ObjectStoreInfo]() ObjectStoreInfo defines model for ObjectStoreInfo. @@ -4307,7 +4310,7 @@ type ObjectStoreInfo struct { ``` -## type [PingCollectionResponse]() +## type [PingCollectionResponse]() PingCollectionResponse defines model for PingCollectionResponse. @@ -4320,7 +4323,7 @@ type PingCollectionResponse struct { ``` -## type [PingResponse]() +## type [PingResponse]() PingResponse defines model for PingResponse. @@ -4838,7 +4841,7 @@ func (r PutNodeNetworkDNSResponse) StatusCode() int StatusCode returns HTTPResponse.StatusCode -## type [QueueStatsResponse]() +## type [QueueStatsResponse]() QueueStatsResponse defines model for QueueStatsResponse. @@ -4847,9 +4850,6 @@ type QueueStatsResponse struct { // DlqCount Number of jobs in the dead letter queue. DlqCount *int `json:"dlq_count,omitempty"` - // OperationCounts Count of jobs by operation type. - OperationCounts *map[string]int `json:"operation_counts,omitempty"` - // StatusCounts Count of jobs by status. StatusCounts *map[string]int `json:"status_counts,omitempty"` diff --git a/docs/gen/osapi.md b/docs/gen/osapi.md index 1b392ea..cf12b2a 100644 --- a/docs/gen/osapi.md +++ b/docs/gen/osapi.md @@ -923,14 +923,15 @@ type JobDetail struct { ``` -## type [JobList]() +## type [JobList]() JobList is a paginated list of jobs. ```go type JobList struct { - Items []JobDetail - TotalItems int + Items []JobDetail + TotalItems int + StatusCounts map[string]int } ``` @@ -1414,16 +1415,15 @@ type PingResult struct { ``` -## type [QueueStats]() +## type [QueueStats]() QueueStats represents job queue statistics. ```go type QueueStats struct { - TotalJobs int - DlqCount int - StatusCounts map[string]int - OperationCounts map[string]int + TotalJobs int + DlqCount int + StatusCounts map[string]int } ``` diff --git a/pkg/osapi/gen/api.yaml b/pkg/osapi/gen/api.yaml index 36c5a29..e7b3ff3 100644 --- a/pkg/osapi/gen/api.yaml +++ b/pkg/osapi/gen/api.yaml @@ -2505,6 +2505,14 @@ components: type: integer description: Total number of jobs matching the filter. example: 42 + status_counts: + type: object + additionalProperties: + type: integer + description: > + Count of all jobs by status (submitted, processing, completed, + failed, partial_failure). Derived from key names during the + listing pass — no extra reads. items: type: array items: @@ -2598,11 +2606,6 @@ components: additionalProperties: type: integer description: Count of jobs by status. - operation_counts: - type: object - additionalProperties: - type: integer - description: Count of jobs by operation type. dlq_count: type: integer description: Number of jobs in the dead letter queue. diff --git a/pkg/osapi/gen/client.gen.go b/pkg/osapi/gen/client.gen.go index 74bf147..fdf62e9 100644 --- a/pkg/osapi/gen/client.gen.go +++ b/pkg/osapi/gen/client.gen.go @@ -697,6 +697,9 @@ type ListAuditResponse struct { type ListJobsResponse struct { Items *[]JobDetailResponse `json:"items,omitempty"` + // StatusCounts Count of all jobs by status (submitted, processing, completed, failed, partial_failure). Derived from key names during the listing pass — no extra reads. + StatusCounts *map[string]int `json:"status_counts,omitempty"` + // TotalItems Total number of jobs matching the filter. TotalItems *int `json:"total_items,omitempty"` } @@ -903,9 +906,6 @@ type QueueStatsResponse struct { // DlqCount Number of jobs in the dead letter queue. DlqCount *int `json:"dlq_count,omitempty"` - // OperationCounts Count of jobs by operation type. - OperationCounts *map[string]int `json:"operation_counts,omitempty"` - // StatusCounts Count of jobs by status. StatusCounts *map[string]int `json:"status_counts,omitempty"` diff --git a/pkg/osapi/job_types.go b/pkg/osapi/job_types.go index e37e494..5023a8d 100644 --- a/pkg/osapi/job_types.go +++ b/pkg/osapi/job_types.go @@ -64,16 +64,16 @@ type AgentJobResponse struct { // JobList is a paginated list of jobs. type JobList struct { - Items []JobDetail - TotalItems int + Items []JobDetail + TotalItems int + StatusCounts map[string]int } // QueueStats represents job queue statistics. type QueueStats struct { - TotalJobs int - DlqCount int - StatusCounts map[string]int - OperationCounts map[string]int + TotalJobs int + DlqCount int + StatusCounts map[string]int } // jobCreatedFromGen converts a gen.CreateJobResponse to a JobCreated. @@ -224,6 +224,10 @@ func jobListFromGen( jl.TotalItems = *g.TotalItems } + if g.StatusCounts != nil { + jl.StatusCounts = *g.StatusCounts + } + if g.Items != nil { items := make([]JobDetail, 0, len(*g.Items)) for i := range *g.Items { @@ -254,9 +258,5 @@ func queueStatsFromGen( qs.StatusCounts = *g.StatusCounts } - if g.OperationCounts != nil { - qs.OperationCounts = *g.OperationCounts - } - return qs } diff --git a/pkg/osapi/job_types_test.go b/pkg/osapi/job_types_test.go index f446d71..5c95206 100644 --- a/pkg/osapi/job_types_test.go +++ b/pkg/osapi/job_types_test.go @@ -241,6 +241,10 @@ func (suite *JobTypesTestSuite) TestJobListFromGen() { id := openapi_types.UUID(uuid.MustParse("44444444-4444-4444-4444-444444444444")) status := "pending" totalItems := 1 + statusCounts := map[string]int{ + "pending": 1, + "completed": 0, + } items := []gen.JobDetailResponse{ { Id: &id, @@ -249,12 +253,17 @@ func (suite *JobTypesTestSuite) TestJobListFromGen() { } return &gen.ListJobsResponse{ - Items: &items, - TotalItems: &totalItems, + Items: &items, + TotalItems: &totalItems, + StatusCounts: &statusCounts, } }(), validateFunc: func(jl JobList) { suite.Equal(1, jl.TotalItems) + suite.Equal(map[string]int{ + "pending": 1, + "completed": 0, + }, jl.StatusCounts) suite.Len(jl.Items, 1) suite.Equal("44444444-4444-4444-4444-444444444444", jl.Items[0].ID) suite.Equal("pending", jl.Items[0].Status) @@ -281,6 +290,7 @@ func (suite *JobTypesTestSuite) TestJobListFromGen() { input: &gen.ListJobsResponse{}, validateFunc: func(jl JobList) { suite.Equal(0, jl.TotalItems) + suite.Nil(jl.StatusCounts) suite.Nil(jl.Items) }, }, @@ -310,16 +320,11 @@ func (suite *JobTypesTestSuite) TestQueueStatsFromGen() { "completed": 60, "failed": 10, } - operationCounts := map[string]int{ - "node.hostname": 50, - "node.disk": 50, - } return &gen.QueueStatsResponse{ - TotalJobs: &totalJobs, - DlqCount: &dlqCount, - StatusCounts: &statusCounts, - OperationCounts: &operationCounts, + TotalJobs: &totalJobs, + DlqCount: &dlqCount, + StatusCounts: &statusCounts, } }(), validateFunc: func(qs QueueStats) { @@ -330,10 +335,6 @@ func (suite *JobTypesTestSuite) TestQueueStatsFromGen() { "completed": 60, "failed": 10, }, qs.StatusCounts) - suite.Equal(map[string]int{ - "node.hostname": 50, - "node.disk": 50, - }, qs.OperationCounts) }, }, { @@ -343,7 +344,6 @@ func (suite *JobTypesTestSuite) TestQueueStatsFromGen() { suite.Equal(0, qs.TotalJobs) suite.Equal(0, qs.DlqCount) suite.Nil(qs.StatusCounts) - suite.Nil(qs.OperationCounts) }, }, }