mirror of
https://github.com/hatchet-dev/hatchet.git
synced 2026-04-23 10:39:45 -05:00
feat: add endpoint for listing queue metrics (#615)
* wip: create openapi endpoint for queue metrics * feat: add queue metrics api
This commit is contained in:
@@ -60,6 +60,10 @@ TenantInvite:
|
||||
$ref: "./tenant.yaml#/TenantInvite"
|
||||
TenantInviteList:
|
||||
$ref: "./tenant.yaml#/TenantInviteList"
|
||||
QueueMetrics:
|
||||
$ref: "./tenant.yaml#/QueueMetrics"
|
||||
TenantQueueMetrics:
|
||||
$ref: "./tenant.yaml#/TenantQueueMetrics"
|
||||
AcceptInviteRequest:
|
||||
$ref: "./user.yaml#/AcceptInviteRequest"
|
||||
RejectInviteRequest:
|
||||
|
||||
@@ -304,3 +304,30 @@ TenantInviteList:
|
||||
$ref: "#/TenantInvite"
|
||||
type: array
|
||||
x-go-name: Rows
|
||||
|
||||
QueueMetrics:
|
||||
type: object
|
||||
properties:
|
||||
numQueued:
|
||||
type: integer
|
||||
description: The number of items in the queue.
|
||||
numRunning:
|
||||
type: integer
|
||||
description: The number of items running.
|
||||
numPending:
|
||||
type: integer
|
||||
description: The number of items pending.
|
||||
required:
|
||||
- numQueued
|
||||
- numRunning
|
||||
- numPending
|
||||
|
||||
TenantQueueMetrics:
|
||||
properties:
|
||||
total:
|
||||
$ref: "#/QueueMetrics"
|
||||
description: The total queue metrics.
|
||||
workflow:
|
||||
type: object
|
||||
additionalProperties:
|
||||
$ref: "#/QueueMetrics"
|
||||
|
||||
@@ -96,6 +96,8 @@ paths:
|
||||
$ref: "./paths/api-tokens/api_tokens.yaml#/withTenant"
|
||||
/api/v1/api-tokens/{api-token}:
|
||||
$ref: "./paths/api-tokens/api_tokens.yaml#/revoke"
|
||||
/api/v1/tenants/{tenant}/queue-metrics:
|
||||
$ref: "./paths/tenant/tenant.yaml#/getQueueMetrics"
|
||||
/api/v1/tenants/{tenant}/events:
|
||||
$ref: "./paths/event/event.yaml#/withTenant"
|
||||
/api/v1/tenants/{tenant}/events/replay:
|
||||
|
||||
@@ -559,3 +559,63 @@ member:
|
||||
summary: Delete a tenant member
|
||||
tags:
|
||||
- Tenant
|
||||
getQueueMetrics:
|
||||
get:
|
||||
x-resources: ["tenant"]
|
||||
description: Get the queue metrics for the tenant
|
||||
operationId: tenant:get:queue-metrics
|
||||
parameters:
|
||||
- description: The tenant id
|
||||
in: path
|
||||
name: tenant
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
- description: A list of workflow IDs to filter by
|
||||
in: query
|
||||
name: workflows
|
||||
required: false
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: "../../components/schemas/_index.yaml#/WorkflowID"
|
||||
- description: A list of metadata key value pairs to filter by
|
||||
in: query
|
||||
name: additionalMetadata
|
||||
example: ["key1:value1", "key2:value2"]
|
||||
required: false
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/TenantQueueMetrics"
|
||||
description: Successfully retrieved the workflow version metrics
|
||||
"400":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: A malformed or bad request
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "../../components/schemas/_index.yaml#/APIErrors"
|
||||
description: Not found
|
||||
summary: Get workflow metrics
|
||||
tags:
|
||||
- Workflow
|
||||
|
||||
@@ -305,17 +305,17 @@ cancelWorkflowRuns:
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
workflowRunIds:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
workflowRunIds:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
description: Successfully cancelled the workflow runs
|
||||
"400":
|
||||
content:
|
||||
@@ -773,7 +773,7 @@ getMetrics:
|
||||
format: uuid
|
||||
minLength: 36
|
||||
maxLength: 36
|
||||
- description: A status of workflow runs to filter by
|
||||
- description: A status of workflow run statuses to filter by
|
||||
in: query
|
||||
name: status
|
||||
required: false
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
package tenants
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/apierrors"
|
||||
"github.com/hatchet-dev/hatchet/api/v1/server/oas/gen"
|
||||
"github.com/hatchet-dev/hatchet/pkg/repository"
|
||||
"github.com/hatchet-dev/hatchet/pkg/repository/prisma/db"
|
||||
)
|
||||
|
||||
func (t *TenantService) TenantGetQueueMetrics(ctx echo.Context, request gen.TenantGetQueueMetricsRequestObject) (gen.TenantGetQueueMetricsResponseObject, error) {
|
||||
tenant := ctx.Get("tenant").(*db.TenantModel)
|
||||
|
||||
opts := repository.GetQueueMetricsOpts{}
|
||||
|
||||
if request.Params.AdditionalMetadata != nil {
|
||||
additionalMetadata := make(map[string]interface{}, len(*request.Params.AdditionalMetadata))
|
||||
|
||||
for _, v := range *request.Params.AdditionalMetadata {
|
||||
splitValue := strings.Split(fmt.Sprintf("%v", v), ":")
|
||||
|
||||
if len(splitValue) == 2 {
|
||||
additionalMetadata[splitValue[0]] = splitValue[1]
|
||||
} else {
|
||||
return gen.TenantGetQueueMetrics400JSONResponse(apierrors.NewAPIErrors("Additional metadata filters must be in the format key:value.")), nil
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
opts.AdditionalMetadata = additionalMetadata
|
||||
}
|
||||
|
||||
if request.Params.Workflows != nil {
|
||||
opts.WorkflowIds = *request.Params.Workflows
|
||||
}
|
||||
|
||||
metrics, err := t.config.APIRepository.Tenant().GetQueueMetrics(tenant.ID, &opts)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
respWorkflowMap := make(map[string]gen.QueueMetrics, len(metrics.ByWorkflowId))
|
||||
|
||||
for k, v := range metrics.ByWorkflowId {
|
||||
respWorkflowMap[k] = gen.QueueMetrics{
|
||||
NumPending: v.Pending,
|
||||
NumQueued: v.PendingAssignment,
|
||||
NumRunning: v.Running,
|
||||
}
|
||||
}
|
||||
|
||||
resp := gen.TenantQueueMetrics{
|
||||
Total: &gen.QueueMetrics{
|
||||
NumPending: metrics.Total.Pending,
|
||||
NumQueued: metrics.Total.PendingAssignment,
|
||||
NumRunning: metrics.Total.Running,
|
||||
},
|
||||
Workflow: &respWorkflowMap,
|
||||
}
|
||||
|
||||
return gen.TenantGetQueueMetrics200JSONResponse(resp), nil
|
||||
}
|
||||
@@ -510,6 +510,18 @@ type PullRequest struct {
|
||||
// PullRequestState defines model for PullRequestState.
|
||||
type PullRequestState string
|
||||
|
||||
// QueueMetrics defines model for QueueMetrics.
|
||||
type QueueMetrics struct {
|
||||
// NumPending The number of items pending.
|
||||
NumPending int `json:"numPending"`
|
||||
|
||||
// NumQueued The number of items in the queue.
|
||||
NumQueued int `json:"numQueued"`
|
||||
|
||||
// NumRunning The number of items running.
|
||||
NumRunning int `json:"numRunning"`
|
||||
}
|
||||
|
||||
// RejectInviteRequest defines model for RejectInviteRequest.
|
||||
type RejectInviteRequest struct {
|
||||
Invite string `json:"invite" validate:"required,uuid"`
|
||||
@@ -729,6 +741,12 @@ type TenantMemberList struct {
|
||||
// TenantMemberRole defines model for TenantMemberRole.
|
||||
type TenantMemberRole string
|
||||
|
||||
// TenantQueueMetrics defines model for TenantQueueMetrics.
|
||||
type TenantQueueMetrics struct {
|
||||
Total *QueueMetrics `json:"total,omitempty"`
|
||||
Workflow *map[string]QueueMetrics `json:"workflow,omitempty"`
|
||||
}
|
||||
|
||||
// TenantResource defines model for TenantResource.
|
||||
type TenantResource string
|
||||
|
||||
@@ -1156,6 +1174,15 @@ type EventListParams struct {
|
||||
AdditionalMetadata *[]string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
|
||||
}
|
||||
|
||||
// TenantGetQueueMetricsParams defines parameters for TenantGetQueueMetrics.
|
||||
type TenantGetQueueMetricsParams struct {
|
||||
// Workflows A list of workflow IDs to filter by
|
||||
Workflows *[]WorkflowID `form:"workflows,omitempty" json:"workflows,omitempty"`
|
||||
|
||||
// AdditionalMetadata A list of metadata key value pairs to filter by
|
||||
AdditionalMetadata *[]string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowRunListPullRequestsParams defines parameters for WorkflowRunListPullRequests.
|
||||
type WorkflowRunListPullRequestsParams struct {
|
||||
// State The pull request state
|
||||
@@ -1209,7 +1236,7 @@ type WorkflowRunGetMetricsParams struct {
|
||||
|
||||
// WorkflowGetMetricsParams defines parameters for WorkflowGetMetrics.
|
||||
type WorkflowGetMetricsParams struct {
|
||||
// Status A status of workflow runs to filter by
|
||||
// Status A status of workflow run statuses to filter by
|
||||
Status *WorkflowRunStatus `form:"status,omitempty" json:"status,omitempty"`
|
||||
|
||||
// GroupKey A group key to filter metrics by
|
||||
@@ -1401,6 +1428,9 @@ type ServerInterface interface {
|
||||
// Delete a tenant member
|
||||
// (DELETE /api/v1/tenants/{tenant}/members/{member})
|
||||
TenantMemberDelete(ctx echo.Context, tenant openapi_types.UUID, member openapi_types.UUID) error
|
||||
// Get workflow metrics
|
||||
// (GET /api/v1/tenants/{tenant}/queue-metrics)
|
||||
TenantGetQueueMetrics(ctx echo.Context, tenant openapi_types.UUID, params TenantGetQueueMetricsParams) error
|
||||
// Create tenant alert email group
|
||||
// (GET /api/v1/tenants/{tenant}/resource-policy)
|
||||
TenantResourcePolicyGet(ctx echo.Context, tenant openapi_types.UUID) error
|
||||
@@ -2342,6 +2372,42 @@ func (w *ServerInterfaceWrapper) TenantMemberDelete(ctx echo.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// TenantGetQueueMetrics converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) TenantGetQueueMetrics(ctx echo.Context) error {
|
||||
var err error
|
||||
// ------------- Path parameter "tenant" -------------
|
||||
var tenant openapi_types.UUID
|
||||
|
||||
err = runtime.BindStyledParameterWithLocation("simple", false, "tenant", runtime.ParamLocationPath, ctx.Param("tenant"), &tenant)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tenant: %s", err))
|
||||
}
|
||||
|
||||
ctx.Set(BearerAuthScopes, []string{})
|
||||
|
||||
ctx.Set(CookieAuthScopes, []string{})
|
||||
|
||||
// Parameter object where we will unmarshal all parameters from the context
|
||||
var params TenantGetQueueMetricsParams
|
||||
// ------------- Optional query parameter "workflows" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "workflows", ctx.QueryParams(), ¶ms.Workflows)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter workflows: %s", err))
|
||||
}
|
||||
|
||||
// ------------- Optional query parameter "additionalMetadata" -------------
|
||||
|
||||
err = runtime.BindQueryParameter("form", true, false, "additionalMetadata", ctx.QueryParams(), ¶ms.AdditionalMetadata)
|
||||
if err != nil {
|
||||
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter additionalMetadata: %s", err))
|
||||
}
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.TenantGetQueueMetrics(ctx, tenant, params)
|
||||
return err
|
||||
}
|
||||
|
||||
// TenantResourcePolicyGet converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) TenantResourcePolicyGet(ctx echo.Context) error {
|
||||
var err error
|
||||
@@ -3247,6 +3313,7 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
router.PATCH(baseURL+"/api/v1/tenants/:tenant/invites/:tenant-invite", wrapper.TenantInviteUpdate)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/members", wrapper.TenantMemberList)
|
||||
router.DELETE(baseURL+"/api/v1/tenants/:tenant/members/:member", wrapper.TenantMemberDelete)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/queue-metrics", wrapper.TenantGetQueueMetrics)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/resource-policy", wrapper.TenantResourcePolicyGet)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/slack", wrapper.SlackWebhookList)
|
||||
router.GET(baseURL+"/api/v1/tenants/:tenant/slack/start", wrapper.UserUpdateSlackOauthStart)
|
||||
@@ -4613,6 +4680,51 @@ func (response TenantMemberDelete404JSONResponse) VisitTenantMemberDeleteRespons
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type TenantGetQueueMetricsRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
Params TenantGetQueueMetricsParams
|
||||
}
|
||||
|
||||
type TenantGetQueueMetricsResponseObject interface {
|
||||
VisitTenantGetQueueMetricsResponse(w http.ResponseWriter) error
|
||||
}
|
||||
|
||||
type TenantGetQueueMetrics200JSONResponse TenantQueueMetrics
|
||||
|
||||
func (response TenantGetQueueMetrics200JSONResponse) VisitTenantGetQueueMetricsResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(200)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type TenantGetQueueMetrics400JSONResponse APIErrors
|
||||
|
||||
func (response TenantGetQueueMetrics400JSONResponse) VisitTenantGetQueueMetricsResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(400)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type TenantGetQueueMetrics403JSONResponse APIErrors
|
||||
|
||||
func (response TenantGetQueueMetrics403JSONResponse) VisitTenantGetQueueMetricsResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(403)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type TenantGetQueueMetrics404JSONResponse APIErrors
|
||||
|
||||
func (response TenantGetQueueMetrics404JSONResponse) VisitTenantGetQueueMetricsResponse(w http.ResponseWriter) error {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(404)
|
||||
|
||||
return json.NewEncoder(w).Encode(response)
|
||||
}
|
||||
|
||||
type TenantResourcePolicyGetRequestObject struct {
|
||||
Tenant openapi_types.UUID `json:"tenant"`
|
||||
}
|
||||
@@ -6141,6 +6253,8 @@ type StrictServerInterface interface {
|
||||
|
||||
TenantMemberDelete(ctx echo.Context, request TenantMemberDeleteRequestObject) (TenantMemberDeleteResponseObject, error)
|
||||
|
||||
TenantGetQueueMetrics(ctx echo.Context, request TenantGetQueueMetricsRequestObject) (TenantGetQueueMetricsResponseObject, error)
|
||||
|
||||
TenantResourcePolicyGet(ctx echo.Context, request TenantResourcePolicyGetRequestObject) (TenantResourcePolicyGetResponseObject, error)
|
||||
|
||||
SlackWebhookList(ctx echo.Context, request SlackWebhookListRequestObject) (SlackWebhookListResponseObject, error)
|
||||
@@ -7182,6 +7296,32 @@ func (sh *strictHandler) TenantMemberDelete(ctx echo.Context, tenant openapi_typ
|
||||
return nil
|
||||
}
|
||||
|
||||
// TenantGetQueueMetrics operation middleware
|
||||
func (sh *strictHandler) TenantGetQueueMetrics(ctx echo.Context, tenant openapi_types.UUID, params TenantGetQueueMetricsParams) error {
|
||||
var request TenantGetQueueMetricsRequestObject
|
||||
|
||||
request.Tenant = tenant
|
||||
request.Params = params
|
||||
|
||||
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
|
||||
return sh.ssi.TenantGetQueueMetrics(ctx, request.(TenantGetQueueMetricsRequestObject))
|
||||
}
|
||||
for _, middleware := range sh.middlewares {
|
||||
handler = middleware(handler, "TenantGetQueueMetrics")
|
||||
}
|
||||
|
||||
response, err := handler(ctx, request)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else if validResponse, ok := response.(TenantGetQueueMetricsResponseObject); ok {
|
||||
return validResponse.VisitTenantGetQueueMetricsResponse(ctx.Response())
|
||||
} else if response != nil {
|
||||
return fmt.Errorf("Unexpected response type: %T", response)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TenantResourcePolicyGet operation middleware
|
||||
func (sh *strictHandler) TenantResourcePolicyGet(ctx echo.Context, tenant openapi_types.UUID) error {
|
||||
var request TenantResourcePolicyGetRequestObject
|
||||
@@ -8226,166 +8366,168 @@ func (sh *strictHandler) WorkflowVersionGetDefinition(ctx echo.Context, workflow
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"W3R/AQA=",
|
||||
"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",
|
||||
"33+6fvrfAAAA//+BhLEjmoYBAA==",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
||||
@@ -58,6 +58,7 @@ import {
|
||||
TenantInviteList,
|
||||
TenantMember,
|
||||
TenantMemberList,
|
||||
TenantQueueMetrics,
|
||||
TenantResourcePolicy,
|
||||
TriggerWorkflowRunRequest,
|
||||
UpdateTenantAlertEmailGroupRequest,
|
||||
@@ -824,6 +825,36 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
|
||||
secure: true,
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Get the queue metrics for the tenant
|
||||
*
|
||||
* @tags Workflow
|
||||
* @name TenantGetQueueMetrics
|
||||
* @summary Get workflow metrics
|
||||
* @request GET:/api/v1/tenants/{tenant}/queue-metrics
|
||||
* @secure
|
||||
*/
|
||||
tenantGetQueueMetrics = (
|
||||
tenant: string,
|
||||
query?: {
|
||||
/** A list of workflow IDs to filter by */
|
||||
workflows?: WorkflowID[];
|
||||
/**
|
||||
* A list of metadata key value pairs to filter by
|
||||
* @example ["key1:value1","key2:value2"]
|
||||
*/
|
||||
additionalMetadata?: string[];
|
||||
},
|
||||
params: RequestParams = {},
|
||||
) =>
|
||||
this.request<TenantQueueMetrics, APIErrors>({
|
||||
path: `/api/v1/tenants/${tenant}/queue-metrics`,
|
||||
method: "GET",
|
||||
query: query,
|
||||
secure: true,
|
||||
format: "json",
|
||||
...params,
|
||||
});
|
||||
/**
|
||||
* @description Lists all events for a tenant.
|
||||
*
|
||||
@@ -1159,7 +1190,7 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
|
||||
workflowGetMetrics = (
|
||||
workflow: string,
|
||||
query?: {
|
||||
/** A status of workflow runs to filter by */
|
||||
/** A status of workflow run statuses to filter by */
|
||||
status?: WorkflowRunStatus;
|
||||
/** A group key to filter metrics by */
|
||||
groupKey?: string;
|
||||
|
||||
@@ -325,6 +325,21 @@ export interface TenantInviteList {
|
||||
rows?: TenantInvite[];
|
||||
}
|
||||
|
||||
export interface QueueMetrics {
|
||||
/** The number of items in the queue. */
|
||||
numQueued: number;
|
||||
/** The number of items running. */
|
||||
numRunning: number;
|
||||
/** The number of items pending. */
|
||||
numPending: number;
|
||||
}
|
||||
|
||||
export interface TenantQueueMetrics {
|
||||
/** The total queue metrics. */
|
||||
total?: QueueMetrics;
|
||||
workflow?: Record<string, QueueMetrics>;
|
||||
}
|
||||
|
||||
export interface AcceptInviteRequest {
|
||||
/**
|
||||
* @minLength 36
|
||||
|
||||
+199
-1
@@ -507,6 +507,18 @@ type PullRequest struct {
|
||||
// PullRequestState defines model for PullRequestState.
|
||||
type PullRequestState string
|
||||
|
||||
// QueueMetrics defines model for QueueMetrics.
|
||||
type QueueMetrics struct {
|
||||
// NumPending The number of items pending.
|
||||
NumPending int `json:"numPending"`
|
||||
|
||||
// NumQueued The number of items in the queue.
|
||||
NumQueued int `json:"numQueued"`
|
||||
|
||||
// NumRunning The number of items running.
|
||||
NumRunning int `json:"numRunning"`
|
||||
}
|
||||
|
||||
// RejectInviteRequest defines model for RejectInviteRequest.
|
||||
type RejectInviteRequest struct {
|
||||
Invite string `json:"invite" validate:"required,uuid"`
|
||||
@@ -726,6 +738,12 @@ type TenantMemberList struct {
|
||||
// TenantMemberRole defines model for TenantMemberRole.
|
||||
type TenantMemberRole string
|
||||
|
||||
// TenantQueueMetrics defines model for TenantQueueMetrics.
|
||||
type TenantQueueMetrics struct {
|
||||
Total *QueueMetrics `json:"total,omitempty"`
|
||||
Workflow *map[string]QueueMetrics `json:"workflow,omitempty"`
|
||||
}
|
||||
|
||||
// TenantResource defines model for TenantResource.
|
||||
type TenantResource string
|
||||
|
||||
@@ -1153,6 +1171,15 @@ type EventListParams struct {
|
||||
AdditionalMetadata *[]string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
|
||||
}
|
||||
|
||||
// TenantGetQueueMetricsParams defines parameters for TenantGetQueueMetrics.
|
||||
type TenantGetQueueMetricsParams struct {
|
||||
// Workflows A list of workflow IDs to filter by
|
||||
Workflows *[]WorkflowID `form:"workflows,omitempty" json:"workflows,omitempty"`
|
||||
|
||||
// AdditionalMetadata A list of metadata key value pairs to filter by
|
||||
AdditionalMetadata *[]string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
|
||||
}
|
||||
|
||||
// WorkflowRunListPullRequestsParams defines parameters for WorkflowRunListPullRequests.
|
||||
type WorkflowRunListPullRequestsParams struct {
|
||||
// State The pull request state
|
||||
@@ -1206,7 +1233,7 @@ type WorkflowRunGetMetricsParams struct {
|
||||
|
||||
// WorkflowGetMetricsParams defines parameters for WorkflowGetMetrics.
|
||||
type WorkflowGetMetricsParams struct {
|
||||
// Status A status of workflow runs to filter by
|
||||
// Status A status of workflow run statuses to filter by
|
||||
Status *WorkflowRunStatus `form:"status,omitempty" json:"status,omitempty"`
|
||||
|
||||
// GroupKey A group key to filter metrics by
|
||||
@@ -1487,6 +1514,9 @@ type ClientInterface interface {
|
||||
// TenantMemberDelete request
|
||||
TenantMemberDelete(ctx context.Context, tenant openapi_types.UUID, member openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
// TenantGetQueueMetrics request
|
||||
TenantGetQueueMetrics(ctx context.Context, tenant openapi_types.UUID, params *TenantGetQueueMetricsParams, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
// TenantResourcePolicyGet request
|
||||
TenantResourcePolicyGet(ctx context.Context, tenant openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||
|
||||
@@ -2168,6 +2198,18 @@ func (c *Client) TenantMemberDelete(ctx context.Context, tenant openapi_types.UU
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *Client) TenantGetQueueMetrics(ctx context.Context, tenant openapi_types.UUID, params *TenantGetQueueMetricsParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewTenantGetQueueMetricsRequest(c.Server, tenant, params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req = req.WithContext(ctx)
|
||||
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c.Client.Do(req)
|
||||
}
|
||||
|
||||
func (c *Client) TenantResourcePolicyGet(ctx context.Context, tenant openapi_types.UUID, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||
req, err := NewTenantResourcePolicyGetRequest(c.Server, tenant)
|
||||
if err != nil {
|
||||
@@ -4392,6 +4434,78 @@ func NewTenantMemberDeleteRequest(server string, tenant openapi_types.UUID, memb
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewTenantGetQueueMetricsRequest generates requests for TenantGetQueueMetrics
|
||||
func NewTenantGetQueueMetricsRequest(server string, tenant openapi_types.UUID, params *TenantGetQueueMetricsParams) (*http.Request, error) {
|
||||
var err error
|
||||
|
||||
var pathParam0 string
|
||||
|
||||
pathParam0, err = runtime.StyleParamWithLocation("simple", false, "tenant", runtime.ParamLocationPath, tenant)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
serverURL, err := url.Parse(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
operationPath := fmt.Sprintf("/api/v1/tenants/%s/queue-metrics", pathParam0)
|
||||
if operationPath[0] == '/' {
|
||||
operationPath = "." + operationPath
|
||||
}
|
||||
|
||||
queryURL, err := serverURL.Parse(operationPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if params != nil {
|
||||
queryValues := queryURL.Query()
|
||||
|
||||
if params.Workflows != nil {
|
||||
|
||||
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "workflows", runtime.ParamLocationQuery, *params.Workflows); err != nil {
|
||||
return nil, err
|
||||
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for k, v := range parsed {
|
||||
for _, v2 := range v {
|
||||
queryValues.Add(k, v2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if params.AdditionalMetadata != nil {
|
||||
|
||||
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "additionalMetadata", runtime.ParamLocationQuery, *params.AdditionalMetadata); err != nil {
|
||||
return nil, err
|
||||
} else if parsed, err := url.ParseQuery(queryFrag); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for k, v := range parsed {
|
||||
for _, v2 := range v {
|
||||
queryValues.Add(k, v2)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
queryURL.RawQuery = queryValues.Encode()
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", queryURL.String(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return req, nil
|
||||
}
|
||||
|
||||
// NewTenantResourcePolicyGetRequest generates requests for TenantResourcePolicyGet
|
||||
func NewTenantResourcePolicyGetRequest(server string, tenant openapi_types.UUID) (*http.Request, error) {
|
||||
var err error
|
||||
@@ -6327,6 +6441,9 @@ type ClientWithResponsesInterface interface {
|
||||
// TenantMemberDeleteWithResponse request
|
||||
TenantMemberDeleteWithResponse(ctx context.Context, tenant openapi_types.UUID, member openapi_types.UUID, reqEditors ...RequestEditorFn) (*TenantMemberDeleteResponse, error)
|
||||
|
||||
// TenantGetQueueMetricsWithResponse request
|
||||
TenantGetQueueMetricsWithResponse(ctx context.Context, tenant openapi_types.UUID, params *TenantGetQueueMetricsParams, reqEditors ...RequestEditorFn) (*TenantGetQueueMetricsResponse, error)
|
||||
|
||||
// TenantResourcePolicyGetWithResponse request
|
||||
TenantResourcePolicyGetWithResponse(ctx context.Context, tenant openapi_types.UUID, reqEditors ...RequestEditorFn) (*TenantResourcePolicyGetResponse, error)
|
||||
|
||||
@@ -7328,6 +7445,31 @@ func (r TenantMemberDeleteResponse) StatusCode() int {
|
||||
return 0
|
||||
}
|
||||
|
||||
type TenantGetQueueMetricsResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
JSON200 *TenantQueueMetrics
|
||||
JSON400 *APIErrors
|
||||
JSON403 *APIErrors
|
||||
JSON404 *APIErrors
|
||||
}
|
||||
|
||||
// Status returns HTTPResponse.Status
|
||||
func (r TenantGetQueueMetricsResponse) Status() string {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.Status
|
||||
}
|
||||
return http.StatusText(0)
|
||||
}
|
||||
|
||||
// StatusCode returns HTTPResponse.StatusCode
|
||||
func (r TenantGetQueueMetricsResponse) StatusCode() int {
|
||||
if r.HTTPResponse != nil {
|
||||
return r.HTTPResponse.StatusCode
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type TenantResourcePolicyGetResponse struct {
|
||||
Body []byte
|
||||
HTTPResponse *http.Response
|
||||
@@ -8676,6 +8818,15 @@ func (c *ClientWithResponses) TenantMemberDeleteWithResponse(ctx context.Context
|
||||
return ParseTenantMemberDeleteResponse(rsp)
|
||||
}
|
||||
|
||||
// TenantGetQueueMetricsWithResponse request returning *TenantGetQueueMetricsResponse
|
||||
func (c *ClientWithResponses) TenantGetQueueMetricsWithResponse(ctx context.Context, tenant openapi_types.UUID, params *TenantGetQueueMetricsParams, reqEditors ...RequestEditorFn) (*TenantGetQueueMetricsResponse, error) {
|
||||
rsp, err := c.TenantGetQueueMetrics(ctx, tenant, params, reqEditors...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return ParseTenantGetQueueMetricsResponse(rsp)
|
||||
}
|
||||
|
||||
// TenantResourcePolicyGetWithResponse request returning *TenantResourcePolicyGetResponse
|
||||
func (c *ClientWithResponses) TenantResourcePolicyGetWithResponse(ctx context.Context, tenant openapi_types.UUID, reqEditors ...RequestEditorFn) (*TenantResourcePolicyGetResponse, error) {
|
||||
rsp, err := c.TenantResourcePolicyGet(ctx, tenant, reqEditors...)
|
||||
@@ -10522,6 +10673,53 @@ func ParseTenantMemberDeleteResponse(rsp *http.Response) (*TenantMemberDeleteRes
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ParseTenantGetQueueMetricsResponse parses an HTTP response from a TenantGetQueueMetricsWithResponse call
|
||||
func ParseTenantGetQueueMetricsResponse(rsp *http.Response) (*TenantGetQueueMetricsResponse, error) {
|
||||
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||
defer func() { _ = rsp.Body.Close() }()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
response := &TenantGetQueueMetricsResponse{
|
||||
Body: bodyBytes,
|
||||
HTTPResponse: rsp,
|
||||
}
|
||||
|
||||
switch {
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
|
||||
var dest TenantQueueMetrics
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON200 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
|
||||
var dest APIErrors
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON400 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 403:
|
||||
var dest APIErrors
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON403 = &dest
|
||||
|
||||
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 404:
|
||||
var dest APIErrors
|
||||
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.JSON404 = &dest
|
||||
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// ParseTenantResourcePolicyGetResponse parses an HTTP response from a TenantResourcePolicyGetWithResponse call
|
||||
func ParseTenantResourcePolicyGetResponse(rsp *http.Response) (*TenantResourcePolicyGetResponse, error) {
|
||||
bodyBytes, err := io.ReadAll(rsp.Body)
|
||||
|
||||
@@ -51,3 +51,80 @@ SET
|
||||
WHERE
|
||||
"tenantId" = sqlc.arg('tenantId')::uuid
|
||||
RETURNING *;
|
||||
|
||||
-- name: GetTenantTotalQueueMetrics :one
|
||||
WITH valid_workflow_runs AS (
|
||||
SELECT
|
||||
runs."id", workflow."id" as "workflowId", workflow."name" as "workflowName"
|
||||
FROM
|
||||
"WorkflowRun" as runs
|
||||
LEFT JOIN
|
||||
"WorkflowVersion" as workflowVersion ON runs."workflowVersionId" = workflowVersion."id"
|
||||
LEFT JOIN
|
||||
"Workflow" as workflow ON workflowVersion."workflowId" = workflow."id"
|
||||
WHERE
|
||||
-- status of the workflow run must be pending, queued or running
|
||||
runs."status" IN ('PENDING', 'QUEUED', 'RUNNING') AND
|
||||
runs."tenantId" = $1 AND
|
||||
(
|
||||
sqlc.narg('additionalMetadata')::jsonb IS NULL OR
|
||||
runs."additionalMetadata" @> sqlc.narg('additionalMetadata')::jsonb
|
||||
) AND
|
||||
(
|
||||
sqlc.narg('workflowIds')::uuid[] IS NULL OR
|
||||
workflow."id" = ANY(sqlc.narg('workflowIds')::uuid[])
|
||||
)
|
||||
)
|
||||
SELECT
|
||||
-- count of step runs in a PENDING_ASSIGNMENT state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING_ASSIGNMENT') as "pendingAssignmentCount",
|
||||
-- count of step runs in a PENDING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING') as "pendingCount",
|
||||
-- count of step runs in a RUNNING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'RUNNING') as "runningCount"
|
||||
FROM
|
||||
valid_workflow_runs as runs
|
||||
LEFT JOIN
|
||||
"JobRun" as jobRun ON runs."id" = jobRun."workflowRunId"
|
||||
LEFT JOIN
|
||||
"StepRun" as stepRun ON jobRun."id" = stepRun."jobRunId";
|
||||
|
||||
-- name: GetTenantWorkflowQueueMetrics :many
|
||||
WITH valid_workflow_runs AS (
|
||||
SELECT
|
||||
runs."id", workflow."id" as "workflowId", workflow."name" as "workflowName"
|
||||
FROM
|
||||
"WorkflowRun" as runs
|
||||
LEFT JOIN
|
||||
"WorkflowVersion" as workflowVersion ON runs."workflowVersionId" = workflowVersion."id"
|
||||
LEFT JOIN
|
||||
"Workflow" as workflow ON workflowVersion."workflowId" = workflow."id"
|
||||
WHERE
|
||||
-- status of the workflow run must be pending, queued or running
|
||||
runs."status" IN ('PENDING', 'QUEUED', 'RUNNING') AND
|
||||
runs."tenantId" = $1 AND
|
||||
(
|
||||
sqlc.narg('additionalMetadata')::jsonb IS NULL OR
|
||||
runs."additionalMetadata" @> sqlc.narg('additionalMetadata')::jsonb
|
||||
) AND
|
||||
(
|
||||
sqlc.narg('workflowIds')::uuid[] IS NULL OR
|
||||
workflow."id" = ANY(sqlc.narg('workflowIds')::uuid[])
|
||||
)
|
||||
)
|
||||
SELECT
|
||||
runs."workflowId",
|
||||
-- count of step runs in a PENDING_ASSIGNMENT state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING_ASSIGNMENT') as "pendingAssignmentCount",
|
||||
-- count of step runs in a PENDING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING') as "pendingCount",
|
||||
-- count of step runs in a RUNNING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'RUNNING') as "runningCount"
|
||||
FROM
|
||||
valid_workflow_runs as runs
|
||||
LEFT JOIN
|
||||
"JobRun" as jobRun ON runs."id" = jobRun."workflowRunId"
|
||||
LEFT JOIN
|
||||
"StepRun" as stepRun ON jobRun."id" = stepRun."jobRunId"
|
||||
GROUP BY
|
||||
runs."workflowId";
|
||||
|
||||
@@ -168,6 +168,142 @@ func (q *Queries) GetTenantByID(ctx context.Context, db DBTX, id pgtype.UUID) (*
|
||||
return &i, err
|
||||
}
|
||||
|
||||
const getTenantTotalQueueMetrics = `-- name: GetTenantTotalQueueMetrics :one
|
||||
WITH valid_workflow_runs AS (
|
||||
SELECT
|
||||
runs."id", workflow."id" as "workflowId", workflow."name" as "workflowName"
|
||||
FROM
|
||||
"WorkflowRun" as runs
|
||||
LEFT JOIN
|
||||
"WorkflowVersion" as workflowVersion ON runs."workflowVersionId" = workflowVersion."id"
|
||||
LEFT JOIN
|
||||
"Workflow" as workflow ON workflowVersion."workflowId" = workflow."id"
|
||||
WHERE
|
||||
-- status of the workflow run must be pending, queued or running
|
||||
runs."status" IN ('PENDING', 'QUEUED', 'RUNNING') AND
|
||||
runs."tenantId" = $1 AND
|
||||
(
|
||||
$2::jsonb IS NULL OR
|
||||
runs."additionalMetadata" @> $2::jsonb
|
||||
) AND
|
||||
(
|
||||
$3::uuid[] IS NULL OR
|
||||
workflow."id" = ANY($3::uuid[])
|
||||
)
|
||||
)
|
||||
SELECT
|
||||
-- count of step runs in a PENDING_ASSIGNMENT state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING_ASSIGNMENT') as "pendingAssignmentCount",
|
||||
-- count of step runs in a PENDING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING') as "pendingCount",
|
||||
-- count of step runs in a RUNNING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'RUNNING') as "runningCount"
|
||||
FROM
|
||||
valid_workflow_runs as runs
|
||||
LEFT JOIN
|
||||
"JobRun" as jobRun ON runs."id" = jobRun."workflowRunId"
|
||||
LEFT JOIN
|
||||
"StepRun" as stepRun ON jobRun."id" = stepRun."jobRunId"
|
||||
`
|
||||
|
||||
type GetTenantTotalQueueMetricsParams struct {
|
||||
TenantId pgtype.UUID `json:"tenantId"`
|
||||
AdditionalMetadata []byte `json:"additionalMetadata"`
|
||||
WorkflowIds []pgtype.UUID `json:"workflowIds"`
|
||||
}
|
||||
|
||||
type GetTenantTotalQueueMetricsRow struct {
|
||||
PendingAssignmentCount int64 `json:"pendingAssignmentCount"`
|
||||
PendingCount int64 `json:"pendingCount"`
|
||||
RunningCount int64 `json:"runningCount"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTenantTotalQueueMetrics(ctx context.Context, db DBTX, arg GetTenantTotalQueueMetricsParams) (*GetTenantTotalQueueMetricsRow, error) {
|
||||
row := db.QueryRow(ctx, getTenantTotalQueueMetrics, arg.TenantId, arg.AdditionalMetadata, arg.WorkflowIds)
|
||||
var i GetTenantTotalQueueMetricsRow
|
||||
err := row.Scan(&i.PendingAssignmentCount, &i.PendingCount, &i.RunningCount)
|
||||
return &i, err
|
||||
}
|
||||
|
||||
const getTenantWorkflowQueueMetrics = `-- name: GetTenantWorkflowQueueMetrics :many
|
||||
WITH valid_workflow_runs AS (
|
||||
SELECT
|
||||
runs."id", workflow."id" as "workflowId", workflow."name" as "workflowName"
|
||||
FROM
|
||||
"WorkflowRun" as runs
|
||||
LEFT JOIN
|
||||
"WorkflowVersion" as workflowVersion ON runs."workflowVersionId" = workflowVersion."id"
|
||||
LEFT JOIN
|
||||
"Workflow" as workflow ON workflowVersion."workflowId" = workflow."id"
|
||||
WHERE
|
||||
-- status of the workflow run must be pending, queued or running
|
||||
runs."status" IN ('PENDING', 'QUEUED', 'RUNNING') AND
|
||||
runs."tenantId" = $1 AND
|
||||
(
|
||||
$2::jsonb IS NULL OR
|
||||
runs."additionalMetadata" @> $2::jsonb
|
||||
) AND
|
||||
(
|
||||
$3::uuid[] IS NULL OR
|
||||
workflow."id" = ANY($3::uuid[])
|
||||
)
|
||||
)
|
||||
SELECT
|
||||
runs."workflowId",
|
||||
-- count of step runs in a PENDING_ASSIGNMENT state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING_ASSIGNMENT') as "pendingAssignmentCount",
|
||||
-- count of step runs in a PENDING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'PENDING') as "pendingCount",
|
||||
-- count of step runs in a RUNNING state
|
||||
COUNT(stepRun."id") FILTER (WHERE stepRun."status" = 'RUNNING') as "runningCount"
|
||||
FROM
|
||||
valid_workflow_runs as runs
|
||||
LEFT JOIN
|
||||
"JobRun" as jobRun ON runs."id" = jobRun."workflowRunId"
|
||||
LEFT JOIN
|
||||
"StepRun" as stepRun ON jobRun."id" = stepRun."jobRunId"
|
||||
GROUP BY
|
||||
runs."workflowId"
|
||||
`
|
||||
|
||||
type GetTenantWorkflowQueueMetricsParams struct {
|
||||
TenantId pgtype.UUID `json:"tenantId"`
|
||||
AdditionalMetadata []byte `json:"additionalMetadata"`
|
||||
WorkflowIds []pgtype.UUID `json:"workflowIds"`
|
||||
}
|
||||
|
||||
type GetTenantWorkflowQueueMetricsRow struct {
|
||||
WorkflowId pgtype.UUID `json:"workflowId"`
|
||||
PendingAssignmentCount int64 `json:"pendingAssignmentCount"`
|
||||
PendingCount int64 `json:"pendingCount"`
|
||||
RunningCount int64 `json:"runningCount"`
|
||||
}
|
||||
|
||||
func (q *Queries) GetTenantWorkflowQueueMetrics(ctx context.Context, db DBTX, arg GetTenantWorkflowQueueMetricsParams) ([]*GetTenantWorkflowQueueMetricsRow, error) {
|
||||
rows, err := db.Query(ctx, getTenantWorkflowQueueMetrics, arg.TenantId, arg.AdditionalMetadata, arg.WorkflowIds)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []*GetTenantWorkflowQueueMetricsRow
|
||||
for rows.Next() {
|
||||
var i GetTenantWorkflowQueueMetricsRow
|
||||
if err := rows.Scan(
|
||||
&i.WorkflowId,
|
||||
&i.PendingAssignmentCount,
|
||||
&i.PendingCount,
|
||||
&i.RunningCount,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, &i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listTenants = `-- name: ListTenants :many
|
||||
SELECT
|
||||
id, "createdAt", "updatedAt", "deletedAt", name, slug, "analyticsOptOut", "alertMemberEmails"
|
||||
|
||||
@@ -92,7 +92,7 @@ func NewAPIRepository(client *db.PrismaClient, pool *pgxpool.Pool, fs ...PrismaR
|
||||
apiToken: NewAPITokenRepository(client, opts.v, opts.cache),
|
||||
event: NewEventAPIRepository(client, pool, opts.v, opts.l),
|
||||
log: NewLogAPIRepository(pool, opts.v, opts.l),
|
||||
tenant: NewTenantAPIRepository(client, opts.v, opts.cache),
|
||||
tenant: NewTenantAPIRepository(pool, client, opts.v, opts.l, opts.cache),
|
||||
tenantAlerting: NewTenantAlertingAPIRepository(client, opts.v, opts.cache),
|
||||
tenantInvite: NewTenantInviteRepository(client, opts.v),
|
||||
workflow: NewWorkflowRepository(client, pool, opts.v, opts.l),
|
||||
|
||||
@@ -2,8 +2,10 @@ package prisma
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
"github.com/rs/zerolog"
|
||||
|
||||
@@ -16,16 +18,24 @@ import (
|
||||
)
|
||||
|
||||
type tenantAPIRepository struct {
|
||||
client *db.PrismaClient
|
||||
v validator.Validator
|
||||
cache cache.Cacheable
|
||||
cache cache.Cacheable
|
||||
client *db.PrismaClient
|
||||
pool *pgxpool.Pool
|
||||
v validator.Validator
|
||||
l *zerolog.Logger
|
||||
queries *dbsqlc.Queries
|
||||
}
|
||||
|
||||
func NewTenantAPIRepository(client *db.PrismaClient, v validator.Validator, cache cache.Cacheable) repository.TenantAPIRepository {
|
||||
func NewTenantAPIRepository(pool *pgxpool.Pool, client *db.PrismaClient, v validator.Validator, l *zerolog.Logger, cache cache.Cacheable) repository.TenantAPIRepository {
|
||||
queries := dbsqlc.New()
|
||||
|
||||
return &tenantAPIRepository{
|
||||
client: client,
|
||||
v: v,
|
||||
cache: cache,
|
||||
cache: cache,
|
||||
client: client,
|
||||
pool: pool,
|
||||
v: v,
|
||||
l: l,
|
||||
queries: queries,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,6 +179,82 @@ func (r *tenantAPIRepository) DeleteTenantMember(memberId string) (*db.TenantMem
|
||||
).Delete().Exec(context.Background())
|
||||
}
|
||||
|
||||
func (r *tenantAPIRepository) GetQueueMetrics(tenantId string, opts *repository.GetQueueMetricsOpts) (*repository.GetQueueMetricsResponse, error) {
|
||||
if err := r.v.Validate(opts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalParams := dbsqlc.GetTenantTotalQueueMetricsParams{
|
||||
TenantId: sqlchelpers.UUIDFromStr(tenantId),
|
||||
}
|
||||
|
||||
workflowParams := dbsqlc.GetTenantWorkflowQueueMetricsParams{
|
||||
TenantId: sqlchelpers.UUIDFromStr(tenantId),
|
||||
}
|
||||
|
||||
if opts.AdditionalMetadata != nil {
|
||||
additionalMetadataBytes, err := json.Marshal(opts.AdditionalMetadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
totalParams.AdditionalMetadata = additionalMetadataBytes
|
||||
workflowParams.AdditionalMetadata = additionalMetadataBytes
|
||||
}
|
||||
|
||||
if opts.WorkflowIds != nil {
|
||||
uuids := make([]pgtype.UUID, len(opts.WorkflowIds))
|
||||
|
||||
for i, id := range opts.WorkflowIds {
|
||||
uuids[i] = sqlchelpers.UUIDFromStr(id)
|
||||
}
|
||||
|
||||
workflowParams.WorkflowIds = uuids
|
||||
totalParams.WorkflowIds = uuids
|
||||
}
|
||||
|
||||
tx, err := r.pool.Begin(context.Background())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer deferRollback(context.Background(), r.l, tx.Rollback)
|
||||
|
||||
// get the totals
|
||||
total, err := r.queries.GetTenantTotalQueueMetrics(context.Background(), tx, totalParams)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// get the workflow metrics
|
||||
workflowMetrics, err := r.queries.GetTenantWorkflowQueueMetrics(context.Background(), tx, workflowParams)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
workflowMetricsMap := make(map[string]repository.QueueMetric)
|
||||
|
||||
for _, metric := range workflowMetrics {
|
||||
workflowMetricsMap[sqlchelpers.UUIDToStr(metric.WorkflowId)] = repository.QueueMetric{
|
||||
PendingAssignment: int(metric.PendingAssignmentCount),
|
||||
Pending: int(metric.PendingCount),
|
||||
Running: int(metric.RunningCount),
|
||||
}
|
||||
}
|
||||
|
||||
return &repository.GetQueueMetricsResponse{
|
||||
Total: repository.QueueMetric{
|
||||
PendingAssignment: int(total.PendingAssignmentCount),
|
||||
Pending: int(total.PendingCount),
|
||||
Running: int(total.RunningCount),
|
||||
},
|
||||
ByWorkflowId: workflowMetricsMap,
|
||||
}, nil
|
||||
}
|
||||
|
||||
type tenantEngineRepository struct {
|
||||
cache cache.Cacheable
|
||||
pool *pgxpool.Pool
|
||||
|
||||
@@ -35,6 +35,31 @@ type UpdateTenantMemberOpts struct {
|
||||
Role *string `validate:"omitempty,oneof=OWNER ADMIN MEMBER"`
|
||||
}
|
||||
|
||||
type GetQueueMetricsOpts struct {
|
||||
// (optional) a list of workflow ids to filter by
|
||||
WorkflowIds []string `validate:"omitempty,dive,uuid"`
|
||||
|
||||
// (optional) exact metadata to filter by
|
||||
AdditionalMetadata map[string]interface{} `validate:"omitempty"`
|
||||
}
|
||||
|
||||
type QueueMetric struct {
|
||||
// the total number of PENDING_ASSIGNMENT step runs in the queue
|
||||
PendingAssignment int `json:"pending_assignment"`
|
||||
|
||||
// the total number of PENDING step runs in the queue
|
||||
Pending int `json:"pending"`
|
||||
|
||||
// the total number of RUNNING step runs in the queue
|
||||
Running int `json:"running"`
|
||||
}
|
||||
|
||||
type GetQueueMetricsResponse struct {
|
||||
Total QueueMetric `json:"total"`
|
||||
|
||||
ByWorkflowId map[string]QueueMetric `json:"by_workflow"`
|
||||
}
|
||||
|
||||
type TenantAPIRepository interface {
|
||||
// CreateTenant creates a new tenant.
|
||||
CreateTenant(opts *CreateTenantOpts) (*db.TenantModel, error)
|
||||
@@ -68,6 +93,9 @@ type TenantAPIRepository interface {
|
||||
|
||||
// DeleteTenantMember deletes the tenant member with the given id
|
||||
DeleteTenantMember(memberId string) (*db.TenantMemberModel, error)
|
||||
|
||||
// GetQueueMetrics returns the queue metrics for the given tenant
|
||||
GetQueueMetrics(tenantId string, opts *GetQueueMetricsOpts) (*GetQueueMetricsResponse, error)
|
||||
}
|
||||
|
||||
type TenantEngineRepository interface {
|
||||
|
||||
Reference in New Issue
Block a user