Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
6 changes: 6 additions & 0 deletions api-contracts/openapi/paths/v1/webhooks/webhook.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,12 @@ V1WebhookGetDeleteReceiveUpdate:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Forbidden
"429":
content:
application/json:
schema:
$ref: "../../../components/schemas/_index.yaml#/APIErrors"
description: Resource limit exceeded for the tenant
summary: Post a webhook message
tags:
- Webhook
Expand Down
10 changes: 10 additions & 0 deletions api-contracts/openapi/paths/worker/worker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,16 @@ withTenant:
type: array
items:
$ref: "../../components/schemas/_index.yaml#/WorkerStatus"
- description: Filter by worker labels

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to not get bitten here again... and or or?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and

in: query
name: labels
required: false
schema:
type: array
items:
type: string
description: The label key-value pairs (delimited by a `:`) to filter by
minLength: 1
responses:
"200":
content:
Expand Down
10 changes: 10 additions & 0 deletions api/v1/server/handlers/v1/webhooks/receive.go
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,16 @@ func (w *V1WebhooksService) V1WebhookReceive(ctx echo.Context, request gen.V1Web
)

if err != nil {
if errors.Is(err, repository.ErrResourceExhausted) {
return gen.V1WebhookReceive429JSONResponse{
Errors: []gen.APIError{
{
Description: "resource limit exceeded: task run or event limit reached for tenant",
},
},
}, nil
}

return nil, fmt.Errorf("failed to ingest event")
Comment thread
mrkaye97 marked this conversation as resolved.
}

Expand Down
35 changes: 35 additions & 0 deletions api/v1/server/handlers/workers/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ package workers
import (
"fmt"
"math"
"strings"
"time"

"github.com/google/uuid"
"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/api/v1/server/oas/transformers"
transformersv1 "github.com/hatchet-dev/hatchet/api/v1/server/oas/transformers/v1"
Expand All @@ -30,6 +32,25 @@ func (t *WorkerService) WorkerList(ctx echo.Context, request gen.WorkerListReque
}
}

func parseLabelFilters(labels *[]string) (keys []string, values []string, err error) {
if labels == nil {
return nil, nil, nil
}

for _, l := range *labels {
split := strings.SplitN(l, ":", 2)

if len(split) != 2 || split[0] == "" || split[1] == "" {
return nil, nil, fmt.Errorf("invalid label filter format: %s, expected key:value", l)
}

keys = append(keys, split[0])
values = append(values, split[1])
}

return keys, values, nil
}

func (t *WorkerService) workerListV0(ctx echo.Context, tenant *sqlcv1.Tenant, request gen.WorkerListRequestObject) (gen.WorkerListResponseObject, error) {
reqCtx := ctx.Request().Context()
tenantId := tenant.ID
Expand Down Expand Up @@ -63,6 +84,13 @@ func (t *WorkerService) workerListV0(ctx echo.Context, tenant *sqlcv1.Tenant, re
opts.Statuses = statuses
}

labelKeys, labelValues, err := parseLabelFilters(request.Params.Labels)
if err != nil {
return gen.WorkerList400JSONResponse(apierrors.NewAPIErrors(err.Error())), nil
}
opts.LabelKeys = labelKeys
opts.LabelValues = labelValues

_, listSpan := telemetry.NewSpan(reqCtx, "worker-service.v0.list-workers")
defer listSpan.End()

Expand Down Expand Up @@ -152,6 +180,13 @@ func (t *WorkerService) workerListV1(ctx echo.Context, tenant *sqlcv1.Tenant, re
opts.Statuses = statuses
}

labelKeys, labelValues, err := parseLabelFilters(request.Params.Labels)
if err != nil {
return gen.WorkerList400JSONResponse(apierrors.NewAPIErrors(err.Error())), nil
}
opts.LabelKeys = labelKeys
opts.LabelValues = labelValues

listCtx, listSpan := telemetry.NewSpan(reqCtx, "worker-service.v1.list-workers")
defer listSpan.End()

Expand Down
754 changes: 387 additions & 367 deletions api/v1/server/oas/gen/openapi.gen.go

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions frontend/app/src/lib/api/generated/Api.ts

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const startedAtKey: WorkerColumnKeys = 'startedAt';
const slotsKey: WorkerColumnKeys = 'slots';
const lastHeartbeatAtKey: WorkerColumnKeys = 'lastHeartbeatAt';
const runtimeKey: WorkerColumnKeys = 'runtime';
const labelsKey: WorkerColumnKeys = 'labels';
export const labelsKey: WorkerColumnKeys = 'labels';

interface WorkerStatusBadgeProps extends BadgeProps {
status?: string;
Expand Down
24 changes: 20 additions & 4 deletions frontend/app/src/pages/main/v1/workers/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import { columns, statusKey, WorkerColumn } from './components/worker-columns';
import {
columns,
labelsKey,
statusKey,
WorkerColumn,
} from './components/worker-columns';
import { ToolbarType } from '@/components/v1/molecules/data-table/data-table-toolbar';
import { DataTable } from '@/components/v1/molecules/data-table/data-table.tsx';
import { EmptyState } from '@/components/v1/molecules/empty-state/empty-state';
Expand All @@ -21,10 +26,12 @@ import { z } from 'zod';
const workersQuerySchema = z
.object({
s: z.array(z.enum(['ACTIVE', 'INACTIVE', 'PAUSED'])).optional(), // status
l: z.array(z.string()).optional(), // labels
})
.default({})
.transform((data) => ({
s: data.s ?? ['ACTIVE', 'PAUSED'],
l: data.l ?? [],
}));

export default function Workers() {
Expand Down Expand Up @@ -52,16 +59,19 @@ function WorkersTable() {
);

const {
state: { s: statuses },
state: { s: statuses, l: labels },
columnFilters,
setColumnFilters,
resetFilters,
} = useZodColumnFilters(workersQuerySchema, paramKey, { s: statusKey });
} = useZodColumnFilters(workersQuerySchema, paramKey, {
s: statusKey,
l: labelsKey,
});

const { pagination, setPagination, limit, offset, setPageSize } =
usePagination({
key: paramKey,
resetPageOnChange: [statuses],
resetPageOnChange: [statuses, labels],
});

const [columnVisibility, setColumnVisibility] =
Expand All @@ -82,6 +92,7 @@ function WorkersTable() {
offset,
limit,
statuses: statuses as WorkerStatus[],
labels: labels.length > 0 ? labels : undefined,
}),
refetchInterval,
});
Expand Down Expand Up @@ -110,6 +121,11 @@ function WorkersTable() {
{ value: 'INACTIVE', label: 'Inactive' },
],
},
{
columnId: labelsKey,
title: 'Labels',
type: ToolbarType.KeyValue,
},
]}
emptyState={
<EmptyState
Expand Down
27 changes: 27 additions & 0 deletions pkg/client/rest/gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

46 changes: 46 additions & 0 deletions pkg/repository/sqlcv1/workers.sql
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,29 @@ WHERE
ELSE 'ACTIVE'
END = ANY(sqlc.narg('statuses')::text[])
)
AND (
sqlc.narg('labelKeys')::text[] IS NULL
OR sqlc.narg('labelValues')::text[] IS NULL
OR (
SELECT BOOL_AND(
EXISTS (
SELECT 1
FROM "WorkerLabel" wl
WHERE wl."workerId" = workers."id"
AND wl."key" = lf.k
AND (
wl."strValue" = lf.v
OR wl."intValue"::text = lf.v
)
)
)
FROM (
SELECT
UNNEST(sqlc.narg('labelKeys')::text[]) AS k,
UNNEST(sqlc.narg('labelValues')::text[]) AS v
) AS lf
Comment on lines +169 to +173

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol

)
)
Comment on lines +153 to +175

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is gonna seq scan but I think it's fine ?

ORDER BY
workers."createdAt" DESC
OFFSET
Expand Down Expand Up @@ -195,6 +218,29 @@ WHERE
WHEN workers."isPaused" = true THEN 'PAUSED'
ELSE 'ACTIVE'
END = ANY(sqlc.narg('statuses')::text[])
)
AND (
sqlc.narg('labelKeys')::text[] IS NULL
OR sqlc.narg('labelValues')::text[] IS NULL
OR (
SELECT BOOL_AND(
EXISTS (
SELECT 1
FROM "WorkerLabel" wl
WHERE wl."workerId" = workers."id"
AND wl."key" = lf.k
AND (
wl."strValue" = lf.v
OR wl."intValue"::text = lf.v
)
)
)
FROM (
SELECT
UNNEST(sqlc.narg('labelKeys')::text[]) AS k,
UNNEST(sqlc.narg('labelValues')::text[]) AS v
) AS lf
Comment thread
mrkaye97 marked this conversation as resolved.
)
);

-- name: GetWorkerById :one
Expand Down
Loading
Loading