feat: improved workflow runs list (#723)

* feat: add duration to wfr

* chore: generate

* feat: sort order

* feat: add column visibility toggle

* chore: gen
This commit is contained in:
Gabe Ruttner
2024-07-15 15:05:57 -07:00
committed by GitHub
parent c935a38708
commit 38a4ce647d
25 changed files with 1038 additions and 187 deletions

View File

@@ -126,6 +126,10 @@ WorkflowRun:
$ref: "./workflow_run.yaml#/WorkflowRun"
WorkflowRunList:
$ref: "./workflow_run.yaml#/WorkflowRunList"
WorkflowRunOrderByField:
$ref: "./workflow_run.yaml#/WorkflowRunOrderByField"
WorkflowRunOrderByDirection:
$ref: "./workflow_run.yaml#/WorkflowRunOrderByDirection"
WorkflowRunsMetrics:
$ref: "./workflow_run.yaml#/WorkflowRunsMetrics"
WorkflowRunsMetricsCounts:

View File

@@ -1,3 +1,17 @@
WorkflowRunOrderByField:
type: string
enum:
- createdAt
- startedAt
- finishedAt
- duration
WorkflowRunOrderByDirection:
type: string
enum:
- ASC
- DESC
WorkflowRun:
type: object
properties:
@@ -30,6 +44,9 @@ WorkflowRun:
finishedAt:
type: string
format: date-time
duration:
type: integer
example: 1000
parentId:
type: string
example: bb214807-246e-43a5-a25d-41761d1cff9e

View File

@@ -413,6 +413,18 @@ workflowRuns:
type: array
items:
type: string
- description: The order by field
in: query
name: orderByField
required: false
schema:
$ref: "../../components/schemas/_index.yaml#/WorkflowRunOrderByField"
- description: The order by direction
in: query
name: orderByDirection
required: false
schema:
$ref: "../../components/schemas/_index.yaml#/WorkflowRunOrderByDirection"
responses:
"200":
content:

View File

@@ -29,6 +29,16 @@ func (t *WorkflowService) WorkflowRunList(ctx echo.Context, request gen.Workflow
OrderDirection: &orderDirection,
}
if request.Params.OrderByField != nil {
orderBy = string(*request.Params.OrderByField)
listOpts.OrderBy = &orderBy
}
if request.Params.OrderByDirection != nil {
orderDirection = string(*request.Params.OrderByDirection)
listOpts.OrderDirection = &orderDirection
}
if request.Params.Limit != nil {
limit = int(*request.Params.Limit)
listOpts.Limit = &limit

View File

@@ -132,6 +132,20 @@ const (
QUEUENEWEST WorkflowConcurrencyLimitStrategy = "QUEUE_NEWEST"
)
// Defines values for WorkflowRunOrderByDirection.
const (
ASC WorkflowRunOrderByDirection = "ASC"
DESC WorkflowRunOrderByDirection = "DESC"
)
// Defines values for WorkflowRunOrderByField.
const (
CreatedAt WorkflowRunOrderByField = "createdAt"
Duration WorkflowRunOrderByField = "duration"
FinishedAt WorkflowRunOrderByField = "finishedAt"
StartedAt WorkflowRunOrderByField = "startedAt"
)
// Defines values for WorkflowRunStatus.
const (
WorkflowRunStatusCANCELLED WorkflowRunStatus = "CANCELLED"
@@ -989,6 +1003,7 @@ type WorkflowMetrics struct {
type WorkflowRun struct {
AdditionalMetadata *map[string]interface{} `json:"additionalMetadata,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
Duration *int `json:"duration,omitempty"`
Error *string `json:"error,omitempty"`
FinishedAt *time.Time `json:"finishedAt,omitempty"`
Input *map[string]interface{} `json:"input,omitempty"`
@@ -1010,6 +1025,12 @@ type WorkflowRunList struct {
Rows *[]WorkflowRun `json:"rows,omitempty"`
}
// WorkflowRunOrderByDirection defines model for WorkflowRunOrderByDirection.
type WorkflowRunOrderByDirection string
// WorkflowRunOrderByField defines model for WorkflowRunOrderByField.
type WorkflowRunOrderByField string
// WorkflowRunStatus defines model for WorkflowRunStatus.
type WorkflowRunStatus string
@@ -1210,6 +1231,12 @@ type WorkflowRunListParams struct {
// AdditionalMetadata A list of metadata key value pairs to filter by
AdditionalMetadata *[]string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
// OrderByField The order by field
OrderByField *WorkflowRunOrderByField `form:"orderByField,omitempty" json:"orderByField,omitempty"`
// OrderByDirection The order by direction
OrderByDirection *WorkflowRunOrderByDirection `form:"orderByDirection,omitempty" json:"orderByDirection,omitempty"`
}
// WorkflowRunGetMetricsParams defines parameters for WorkflowRunGetMetrics.
@@ -2743,6 +2770,20 @@ func (w *ServerInterfaceWrapper) WorkflowRunList(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter additionalMetadata: %s", err))
}
// ------------- Optional query parameter "orderByField" -------------
err = runtime.BindQueryParameter("form", true, false, "orderByField", ctx.QueryParams(), &params.OrderByField)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter orderByField: %s", err))
}
// ------------- Optional query parameter "orderByDirection" -------------
err = runtime.BindQueryParameter("form", true, false, "orderByDirection", ctx.QueryParams(), &params.OrderByDirection)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter orderByDirection: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.WorkflowRunList(ctx, tenant, params)
return err
@@ -8040,160 +8081,161 @@ func (sh *strictHandler) WorkflowVersionGetDefinition(ctx echo.Context, workflow
// Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{
"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",
}
// GetSwagger returns the content of the embedded swagger specification file

View File

@@ -368,12 +368,19 @@ func ToWorkflowRunFromSQLC(row *dbsqlc.ListWorkflowRunsRow) *gen.WorkflowRun {
}
var duration int
if run.Duration.Valid {
duration = int(run.Duration.Int32)
}
res := &gen.WorkflowRun{
Metadata: *toAPIMetadata(workflowRunId, run.CreatedAt.Time, run.UpdatedAt.Time),
DisplayName: &run.DisplayName.String,
TenantId: pgUUIDToStr(run.TenantId),
StartedAt: startedAt,
FinishedAt: finishedAt,
Duration: &duration,
Status: gen.WorkflowRunStatus(run.Status),
WorkflowVersionId: pgUUIDToStr(run.WorkflowVersionId),
WorkflowVersion: workflowVersion,

View File

@@ -76,6 +76,8 @@ import {
WorkflowMetrics,
WorkflowRun,
WorkflowRunList,
WorkflowRunOrderByDirection,
WorkflowRunOrderByField,
WorkflowRunsCancelRequest,
WorkflowRunsMetrics,
WorkflowRunStatus,
@@ -1323,6 +1325,10 @@ export class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType
* @example ["key1:value1","key2:value2"]
*/
additionalMetadata?: string[];
/** The order by field */
orderByField?: WorkflowRunOrderByField;
/** The order by direction */
orderByDirection?: WorkflowRunOrderByDirection;
},
params: RequestParams = {},
) =>

View File

@@ -620,6 +620,8 @@ export interface WorkflowRun {
startedAt?: string;
/** @format date-time */
finishedAt?: string;
/** @example 1000 */
duration?: number;
/**
* @format uuid
* @minLength 36
@@ -642,6 +644,18 @@ export interface WorkflowRunList {
pagination?: PaginationResponse;
}
export enum WorkflowRunOrderByField {
CreatedAt = 'createdAt',
StartedAt = 'startedAt',
FinishedAt = 'finishedAt',
Duration = 'duration',
}
export enum WorkflowRunOrderByDirection {
ASC = 'ASC',
DESC = 'DESC',
}
export interface WorkflowRunsMetrics {
counts?: WorkflowRunsMetricsCounts;
}

View File

@@ -111,7 +111,7 @@ export const columns: ColumnDef<WorkflowRun>[] = [
</div>
);
},
enableSorting: false,
enableSorting: true,
enableHiding: true,
},
{
@@ -134,7 +134,7 @@ export const columns: ColumnDef<WorkflowRun>[] = [
</div>
);
},
enableSorting: false,
enableSorting: true,
enableHiding: true,
},
{
@@ -155,7 +155,22 @@ export const columns: ColumnDef<WorkflowRun>[] = [
return <div className="whitespace-nowrap">{finishedAt}</div>;
},
enableSorting: false,
enableSorting: true,
enableHiding: true,
},
{
accessorKey: 'Duration',
header: ({ column }) => (
<DataTableColumnHeader
column={column}
title="Duration (ms)"
className="whitespace-nowrap"
/>
),
cell: ({ row }) => {
return <div className="whitespace-nowrap">{row.original.duration}</div>;
},
enableSorting: true,
enableHiding: true,
},
{

View File

@@ -10,7 +10,12 @@ import {
} from '@tanstack/react-table';
import { useMutation, useQuery } from '@tanstack/react-query';
import invariant from 'tiny-invariant';
import api, { WorkflowRunStatus, queries } from '@/lib/api';
import api, {
WorkflowRunOrderByDirection,
WorkflowRunOrderByField,
WorkflowRunStatus,
queries,
} from '@/lib/api';
import { Loading } from '@/components/ui/loading.tsx';
import { TenantContextType } from '@/lib/outlet';
import { useOutletContext, useSearchParams } from 'react-router-dom';
@@ -78,11 +83,11 @@ export function WorkflowRunsTable({
const newSearchParams = new URLSearchParams(searchParams);
if (sorting.length) {
newSearchParams.set(
'sort',
'orderDirection',
sorting.map((s) => `${s.id}:${s.desc ? 'desc' : 'asc'}`).join(','),
);
} else {
newSearchParams.delete('sort');
newSearchParams.delete('orderDirection');
}
if (columnFilters.length) {
newSearchParams.set('filters', JSON.stringify(columnFilters));
@@ -142,6 +147,36 @@ export function WorkflowRunsTable({
return filter?.value as Array<string>;
}, [columnFilters]);
const orderByDirection = useMemo(():
| WorkflowRunOrderByDirection
| undefined => {
if (!sorting.length) {
return;
}
return sorting[0]?.desc
? WorkflowRunOrderByDirection.DESC
: WorkflowRunOrderByDirection.ASC;
}, [sorting]);
const orderByField = useMemo((): WorkflowRunOrderByField | undefined => {
if (!sorting.length) {
return;
}
switch (sorting[0]?.id) {
case 'Duration':
return WorkflowRunOrderByField.Duration;
case 'Finished at':
return WorkflowRunOrderByField.FinishedAt;
case 'Started at':
return WorkflowRunOrderByField.StartedAt;
case 'Seen at':
default:
return WorkflowRunOrderByField.CreatedAt;
}
}, [sorting]);
const listWorkflowRunsQuery = useQuery({
...queries.workflowRuns.list(tenant.metadata.id, {
offset,
@@ -150,6 +185,8 @@ export function WorkflowRunsTable({
workflowId: workflow,
parentWorkflowRunId,
parentStepRunId,
orderByDirection,
orderByField,
additionalMetadata: AdditionalMetadataFilter,
}),
refetchInterval,
@@ -355,6 +392,7 @@ export function WorkflowRunsTable({
rowSelection={rowSelection}
setRowSelection={setRowSelection}
pageCount={listWorkflowRunsQuery.data?.pagination?.num_pages || 0}
showColumnToggle={true}
/>
</>
);

View File

@@ -129,6 +129,20 @@ const (
QUEUENEWEST WorkflowConcurrencyLimitStrategy = "QUEUE_NEWEST"
)
// Defines values for WorkflowRunOrderByDirection.
const (
ASC WorkflowRunOrderByDirection = "ASC"
DESC WorkflowRunOrderByDirection = "DESC"
)
// Defines values for WorkflowRunOrderByField.
const (
CreatedAt WorkflowRunOrderByField = "createdAt"
Duration WorkflowRunOrderByField = "duration"
FinishedAt WorkflowRunOrderByField = "finishedAt"
StartedAt WorkflowRunOrderByField = "startedAt"
)
// Defines values for WorkflowRunStatus.
const (
WorkflowRunStatusCANCELLED WorkflowRunStatus = "CANCELLED"
@@ -986,6 +1000,7 @@ type WorkflowMetrics struct {
type WorkflowRun struct {
AdditionalMetadata *map[string]interface{} `json:"additionalMetadata,omitempty"`
DisplayName *string `json:"displayName,omitempty"`
Duration *int `json:"duration,omitempty"`
Error *string `json:"error,omitempty"`
FinishedAt *time.Time `json:"finishedAt,omitempty"`
Input *map[string]interface{} `json:"input,omitempty"`
@@ -1007,6 +1022,12 @@ type WorkflowRunList struct {
Rows *[]WorkflowRun `json:"rows,omitempty"`
}
// WorkflowRunOrderByDirection defines model for WorkflowRunOrderByDirection.
type WorkflowRunOrderByDirection string
// WorkflowRunOrderByField defines model for WorkflowRunOrderByField.
type WorkflowRunOrderByField string
// WorkflowRunStatus defines model for WorkflowRunStatus.
type WorkflowRunStatus string
@@ -1207,6 +1228,12 @@ type WorkflowRunListParams struct {
// AdditionalMetadata A list of metadata key value pairs to filter by
AdditionalMetadata *[]string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
// OrderByField The order by field
OrderByField *WorkflowRunOrderByField `form:"orderByField,omitempty" json:"orderByField,omitempty"`
// OrderByDirection The order by direction
OrderByDirection *WorkflowRunOrderByDirection `form:"orderByDirection,omitempty" json:"orderByDirection,omitempty"`
}
// WorkflowRunGetMetricsParams defines parameters for WorkflowRunGetMetrics.
@@ -5108,6 +5135,38 @@ func NewWorkflowRunListRequest(server string, tenant openapi_types.UUID, params
}
if params.OrderByField != nil {
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "orderByField", runtime.ParamLocationQuery, *params.OrderByField); 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.OrderByDirection != nil {
if queryFrag, err := runtime.StyleParamWithLocation("form", true, "orderByDirection", runtime.ParamLocationQuery, *params.OrderByDirection); 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()
}

View File

@@ -913,6 +913,9 @@ model WorkflowRun {
// the run finished at
finishedAt DateTime?
// the duration of the run (ms)
duration Int?
// a list of dependents for this workflow run
children WorkflowRun[] @relation("WorkflowRunChild")
scheduledChildren WorkflowTriggerScheduledRef[]
@@ -2360,6 +2363,7 @@ const (
WorkflowRunScalarFieldEnumError WorkflowRunScalarFieldEnum = "error"
WorkflowRunScalarFieldEnumStartedAt WorkflowRunScalarFieldEnum = "startedAt"
WorkflowRunScalarFieldEnumFinishedAt WorkflowRunScalarFieldEnum = "finishedAt"
WorkflowRunScalarFieldEnumDuration WorkflowRunScalarFieldEnum = "duration"
WorkflowRunScalarFieldEnumParentID WorkflowRunScalarFieldEnum = "parentId"
WorkflowRunScalarFieldEnumParentStepRunID WorkflowRunScalarFieldEnum = "parentStepRunId"
WorkflowRunScalarFieldEnumChildIndex WorkflowRunScalarFieldEnum = "childIndex"
@@ -3444,6 +3448,8 @@ const workflowRunFieldStartedAt workflowRunPrismaFields = "startedAt"
const workflowRunFieldFinishedAt workflowRunPrismaFields = "finishedAt"
const workflowRunFieldDuration workflowRunPrismaFields = "duration"
const workflowRunFieldChildren workflowRunPrismaFields = "children"
const workflowRunFieldScheduledChildren workflowRunPrismaFields = "scheduledChildren"
@@ -8586,6 +8592,7 @@ type InnerWorkflowRun struct {
Error *string `json:"error,omitempty"`
StartedAt *DateTime `json:"startedAt,omitempty"`
FinishedAt *DateTime `json:"finishedAt,omitempty"`
Duration *int `json:"duration,omitempty"`
ParentID *string `json:"parentId,omitempty"`
ParentStepRunID *string `json:"parentStepRunId,omitempty"`
ChildIndex *int `json:"childIndex,omitempty"`
@@ -8607,6 +8614,7 @@ type RawWorkflowRunModel struct {
Error *RawString `json:"error,omitempty"`
StartedAt *RawDateTime `json:"startedAt,omitempty"`
FinishedAt *RawDateTime `json:"finishedAt,omitempty"`
Duration *RawInt `json:"duration,omitempty"`
ParentID *RawString `json:"parentId,omitempty"`
ParentStepRunID *RawString `json:"parentStepRunId,omitempty"`
ChildIndex *RawInt `json:"childIndex,omitempty"`
@@ -8704,6 +8712,13 @@ func (r WorkflowRunModel) FinishedAt() (value DateTime, ok bool) {
return *r.InnerWorkflowRun.FinishedAt, true
}
func (r WorkflowRunModel) Duration() (value Int, ok bool) {
if r.InnerWorkflowRun.Duration == nil {
return value, false
}
return *r.InnerWorkflowRun.Duration, true
}
func (r WorkflowRunModel) Children() (value []WorkflowRunModel) {
if r.RelationsWorkflowRun.Children == nil {
panic("attempted to access children but did not fetch it using the .With() syntax")
@@ -95648,6 +95663,11 @@ type workflowRunQuery struct {
// @optional
FinishedAt workflowRunQueryFinishedAtDateTime
// Duration
//
// @optional
Duration workflowRunQueryDurationInt
Children workflowRunQueryChildrenRelations
ScheduledChildren workflowRunQueryScheduledChildrenRelations
@@ -100316,6 +100336,450 @@ func (r workflowRunQueryFinishedAtDateTime) Field() workflowRunPrismaFields {
return workflowRunFieldFinishedAt
}
// base struct
type workflowRunQueryDurationInt struct{}
// Set the optional value of Duration
func (r workflowRunQueryDurationInt) Set(value int) workflowRunSetParam {
return workflowRunSetParam{
data: builder.Field{
Name: "duration",
Value: value,
},
}
}
// Set the optional value of Duration dynamically
func (r workflowRunQueryDurationInt) SetIfPresent(value *Int) workflowRunSetParam {
if value == nil {
return workflowRunSetParam{}
}
return r.Set(*value)
}
// Set the optional value of Duration dynamically
func (r workflowRunQueryDurationInt) SetOptional(value *Int) workflowRunSetParam {
if value == nil {
var v *int
return workflowRunSetParam{
data: builder.Field{
Name: "duration",
Value: v,
},
}
}
return r.Set(*value)
}
// Increment the optional value of Duration
func (r workflowRunQueryDurationInt) Increment(value int) workflowRunSetParam {
return workflowRunSetParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
builder.Field{
Name: "increment",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) IncrementIfPresent(value *int) workflowRunSetParam {
if value == nil {
return workflowRunSetParam{}
}
return r.Increment(*value)
}
// Decrement the optional value of Duration
func (r workflowRunQueryDurationInt) Decrement(value int) workflowRunSetParam {
return workflowRunSetParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
builder.Field{
Name: "decrement",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) DecrementIfPresent(value *int) workflowRunSetParam {
if value == nil {
return workflowRunSetParam{}
}
return r.Decrement(*value)
}
// Multiply the optional value of Duration
func (r workflowRunQueryDurationInt) Multiply(value int) workflowRunSetParam {
return workflowRunSetParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
builder.Field{
Name: "multiply",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) MultiplyIfPresent(value *int) workflowRunSetParam {
if value == nil {
return workflowRunSetParam{}
}
return r.Multiply(*value)
}
// Divide the optional value of Duration
func (r workflowRunQueryDurationInt) Divide(value int) workflowRunSetParam {
return workflowRunSetParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
builder.Field{
Name: "divide",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) DivideIfPresent(value *int) workflowRunSetParam {
if value == nil {
return workflowRunSetParam{}
}
return r.Divide(*value)
}
func (r workflowRunQueryDurationInt) Equals(value int) workflowRunWithPrismaDurationEqualsParam {
return workflowRunWithPrismaDurationEqualsParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "equals",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) EqualsIfPresent(value *int) workflowRunWithPrismaDurationEqualsParam {
if value == nil {
return workflowRunWithPrismaDurationEqualsParam{}
}
return r.Equals(*value)
}
func (r workflowRunQueryDurationInt) EqualsOptional(value *Int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "equals",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) IsNull() workflowRunDefaultParam {
var str *string = nil
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "equals",
Value: str,
},
},
},
}
}
func (r workflowRunQueryDurationInt) Order(direction SortOrder) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Value: direction,
},
}
}
func (r workflowRunQueryDurationInt) Cursor(cursor int) workflowRunCursorParam {
return workflowRunCursorParam{
data: builder.Field{
Name: "duration",
Value: cursor,
},
}
}
func (r workflowRunQueryDurationInt) In(value []int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "in",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) InIfPresent(value []int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.In(value)
}
func (r workflowRunQueryDurationInt) NotIn(value []int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "notIn",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) NotInIfPresent(value []int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.NotIn(value)
}
func (r workflowRunQueryDurationInt) Lt(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "lt",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) LtIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.Lt(*value)
}
func (r workflowRunQueryDurationInt) Lte(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "lte",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) LteIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.Lte(*value)
}
func (r workflowRunQueryDurationInt) Gt(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "gt",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) GtIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.Gt(*value)
}
func (r workflowRunQueryDurationInt) Gte(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "gte",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) GteIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.Gte(*value)
}
func (r workflowRunQueryDurationInt) Not(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "not",
Value: value,
},
},
},
}
}
func (r workflowRunQueryDurationInt) NotIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.Not(*value)
}
// deprecated: Use Lt instead.
func (r workflowRunQueryDurationInt) LT(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "lt",
Value: value,
},
},
},
}
}
// deprecated: Use LtIfPresent instead.
func (r workflowRunQueryDurationInt) LTIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.LT(*value)
}
// deprecated: Use Lte instead.
func (r workflowRunQueryDurationInt) LTE(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "lte",
Value: value,
},
},
},
}
}
// deprecated: Use LteIfPresent instead.
func (r workflowRunQueryDurationInt) LTEIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.LTE(*value)
}
// deprecated: Use Gt instead.
func (r workflowRunQueryDurationInt) GT(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "gt",
Value: value,
},
},
},
}
}
// deprecated: Use GtIfPresent instead.
func (r workflowRunQueryDurationInt) GTIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.GT(*value)
}
// deprecated: Use Gte instead.
func (r workflowRunQueryDurationInt) GTE(value int) workflowRunDefaultParam {
return workflowRunDefaultParam{
data: builder.Field{
Name: "duration",
Fields: []builder.Field{
{
Name: "gte",
Value: value,
},
},
},
}
}
// deprecated: Use GteIfPresent instead.
func (r workflowRunQueryDurationInt) GTEIfPresent(value *int) workflowRunDefaultParam {
if value == nil {
return workflowRunDefaultParam{}
}
return r.GTE(*value)
}
func (r workflowRunQueryDurationInt) Field() workflowRunPrismaFields {
return workflowRunFieldDuration
}
// base struct
type workflowRunQueryChildrenWorkflowRun struct{}
@@ -202781,6 +203245,7 @@ var workflowRunOutput = []builder.Output{
{Name: "error"},
{Name: "startedAt"},
{Name: "finishedAt"},
{Name: "duration"},
{Name: "parentId"},
{Name: "parentStepRunId"},
{Name: "childIndex"},
@@ -204278,6 +204743,84 @@ func (p workflowRunWithPrismaFinishedAtEqualsUniqueParam) finishedAtField() {}
func (workflowRunWithPrismaFinishedAtEqualsUniqueParam) unique() {}
func (workflowRunWithPrismaFinishedAtEqualsUniqueParam) equals() {}
type WorkflowRunWithPrismaDurationEqualsSetParam interface {
field() builder.Field
getQuery() builder.Query
equals()
workflowRunModel()
durationField()
}
type WorkflowRunWithPrismaDurationSetParam interface {
field() builder.Field
getQuery() builder.Query
workflowRunModel()
durationField()
}
type workflowRunWithPrismaDurationSetParam struct {
data builder.Field
query builder.Query
}
func (p workflowRunWithPrismaDurationSetParam) field() builder.Field {
return p.data
}
func (p workflowRunWithPrismaDurationSetParam) getQuery() builder.Query {
return p.query
}
func (p workflowRunWithPrismaDurationSetParam) workflowRunModel() {}
func (p workflowRunWithPrismaDurationSetParam) durationField() {}
type WorkflowRunWithPrismaDurationWhereParam interface {
field() builder.Field
getQuery() builder.Query
workflowRunModel()
durationField()
}
type workflowRunWithPrismaDurationEqualsParam struct {
data builder.Field
query builder.Query
}
func (p workflowRunWithPrismaDurationEqualsParam) field() builder.Field {
return p.data
}
func (p workflowRunWithPrismaDurationEqualsParam) getQuery() builder.Query {
return p.query
}
func (p workflowRunWithPrismaDurationEqualsParam) workflowRunModel() {}
func (p workflowRunWithPrismaDurationEqualsParam) durationField() {}
func (workflowRunWithPrismaDurationSetParam) settable() {}
func (workflowRunWithPrismaDurationEqualsParam) equals() {}
type workflowRunWithPrismaDurationEqualsUniqueParam struct {
data builder.Field
query builder.Query
}
func (p workflowRunWithPrismaDurationEqualsUniqueParam) field() builder.Field {
return p.data
}
func (p workflowRunWithPrismaDurationEqualsUniqueParam) getQuery() builder.Query {
return p.query
}
func (p workflowRunWithPrismaDurationEqualsUniqueParam) workflowRunModel() {}
func (p workflowRunWithPrismaDurationEqualsUniqueParam) durationField() {}
func (workflowRunWithPrismaDurationEqualsUniqueParam) unique() {}
func (workflowRunWithPrismaDurationEqualsUniqueParam) equals() {}
type WorkflowRunWithPrismaChildrenEqualsSetParam interface {
field() builder.Field
getQuery() builder.Query

View File

@@ -1093,6 +1093,7 @@ type WorkflowRun struct {
ParentId pgtype.UUID `json:"parentId"`
ParentStepRunId pgtype.UUID `json:"parentStepRunId"`
AdditionalMetadata []byte `json:"additionalMetadata"`
Duration pgtype.Int4 `json:"duration"`
}
type WorkflowRunTriggeredBy struct {

View File

@@ -638,6 +638,7 @@ CREATE TABLE "WorkflowRun" (
"parentId" UUID,
"parentStepRunId" UUID,
"additionalMetadata" JSONB,
"duration" INTEGER,
CONSTRAINT "WorkflowRun_pkey" PRIMARY KEY ("id")
);

View File

@@ -701,7 +701,8 @@ SET
"status" = 'RUNNING',
"updatedAt" = CURRENT_TIMESTAMP,
"startedAt" = NULL,
"finishedAt" = NULL
"finishedAt" = NULL,
"duration" = NULL
WHERE
"id" = (SELECT "workflowRunId" FROM workflow_run_id)
RETURNING *;

View File

@@ -1452,10 +1452,11 @@ SET
"status" = 'RUNNING',
"updatedAt" = CURRENT_TIMESTAMP,
"startedAt" = NULL,
"finishedAt" = NULL
"finishedAt" = NULL,
"duration" = NULL
WHERE
"id" = (SELECT "workflowRunId" FROM workflow_run_id)
RETURNING "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id, "childIndex", "childKey", "parentId", "parentStepRunId", "additionalMetadata"
RETURNING "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id, "childIndex", "childKey", "parentId", "parentStepRunId", "additionalMetadata", duration
`
func (q *Queries) ReplayStepRunResetWorkflowRun(ctx context.Context, db DBTX, jobrunid pgtype.UUID) (*WorkflowRun, error) {
@@ -1479,6 +1480,7 @@ func (q *Queries) ReplayStepRunResetWorkflowRun(ctx context.Context, db DBTX, jo
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
)
return &i, err
}

View File

@@ -174,7 +174,13 @@ WHERE
)
ORDER BY
case when @orderBy = 'createdAt ASC' THEN runs."createdAt" END ASC ,
case when @orderBy = 'createdAt DESC' then runs."createdAt" END DESC,
case when @orderBy = 'createdAt DESC' THEN runs."createdAt" END DESC,
case when @orderBy = 'finishedAt ASC' THEN runs."finishedAt" END ASC ,
case when @orderBy = 'finishedAt DESC' THEN runs."finishedAt" END DESC,
case when @orderBy = 'startedAt ASC' THEN runs."startedAt" END ASC ,
case when @orderBy = 'startedAt DESC' THEN runs."startedAt" END DESC,
case when @orderBy = 'duration ASC' THEN runs."duration" END ASC NULLS FIRST,
case when @orderBy = 'duration DESC' THEN runs."duration" END DESC NULLS LAST,
runs."id" ASC
OFFSET
COALESCE(sqlc.narg('offset'), 0)
@@ -258,13 +264,21 @@ SET "status" = CASE
WHEN groupKeyRun.groupKeyRunStatus IN ('FAILED', 'CANCELLED') THEN 'FAILED'
WHEN groupKeyRun.output IS NOT NULL THEN 'QUEUED'
ELSE "status"
END, "finishedAt" = CASE
END,
"finishedAt" = CASE
-- Final states are final, cannot be updated
WHEN "finishedAt" IS NOT NULL THEN "finishedAt"
-- When one job run has failed or been cancelled, then the workflow is failed
WHEN groupKeyRun.groupKeyRunStatus IN ('FAILED', 'CANCELLED') THEN NOW()
ELSE "finishedAt"
END,
"duration" = CASE
-- duration is final, cannot be changed
WHEN "duration" IS NOT NULL THEN "duration"
WHEN "startedAt" IS NOT NULL AND groupKeyRun.groupKeyRunStatus IN ('FAILED', 'CANCELLED') THEN
EXTRACT(EPOCH FROM (NOW() - "startedAt")) * 1000
ELSE "duration"
END,
"concurrencyGroupId" = groupKeyRun."output"
FROM
groupKeyRun
@@ -303,7 +317,8 @@ SET "status" = CASE
-- When all job runs have succeeded, then the workflow is succeeded
WHEN j.succeededRuns > 0 AND j.pendingRuns = 0 AND j.runningRuns = 0 AND j.failedRuns = 0 AND j.cancelledRuns = 0 THEN 'SUCCEEDED'
ELSE "status"
END, "finishedAt" = CASE
END,
"finishedAt" = CASE
-- Final states are final, cannot be updated
WHEN "finishedAt" IS NOT NULL THEN "finishedAt"
-- We check for running first, because if a job run is running, then the workflow is not finished
@@ -311,12 +326,23 @@ END, "finishedAt" = CASE
-- When one job run has failed or been cancelled, then the workflow is failed
WHEN j.failedRuns > 0 OR j.cancelledRuns > 0 OR j.succeededRuns > 0 THEN NOW()
ELSE "finishedAt"
END, "startedAt" = CASE
END,
"startedAt" = CASE
-- Started at is final, cannot be changed
WHEN "startedAt" IS NOT NULL THEN "startedAt"
-- If a job is running or in a final state, then the workflow has started
WHEN j.runningRuns > 0 OR j.succeededRuns > 0 OR j.failedRuns > 0 OR j.cancelledRuns > 0 THEN NOW()
ELSE "startedAt"
END,
"duration" = CASE
-- duration is final, cannot be changed
WHEN "duration" IS NOT NULL THEN "duration"
-- We check for running first, because if a job run is running, then the workflow is not finished
WHEN j.runningRuns > 0 THEN NULL
-- When one job run has failed or been cancelled, then the workflow is failed
WHEN j.failedRuns > 0 OR j.cancelledRuns > 0 OR j.succeededRuns > 0 THEN
EXTRACT(EPOCH FROM (NOW() - "startedAt")) * 1000
ELSE "duration"
END
FROM
jobRuns j
@@ -338,7 +364,10 @@ SET
END,
"error" = COALESCE(sqlc.narg('error')::text, "error"),
"startedAt" = COALESCE(sqlc.narg('startedAt')::timestamp, "startedAt"),
"finishedAt" = COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt")
"finishedAt" = COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt"),
"duration" =
EXTRACT(EPOCH FROM (COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt") - COALESCE(sqlc.narg('startedAt')::timestamp, "startedAt")) * 1000)
WHERE
"id" = @id::uuid AND
"tenantId" = @tenantId::uuid
@@ -351,7 +380,8 @@ SET
"status" = COALESCE(sqlc.narg('status')::"WorkflowRunStatus", "status"),
"error" = COALESCE(sqlc.narg('error')::text, "error"),
"startedAt" = COALESCE(sqlc.narg('startedAt')::timestamp, "startedAt"),
"finishedAt" = COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt")
"finishedAt" = COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt"),
"duration" = COALESCE(sqlc.narg('finishedAt')::timestamp, "finishedAt") - COALESCE(sqlc.narg('startedAt')::timestamp, "startedAt")
WHERE
"tenantId" = @tenantId::uuid AND
"id" = ANY(@ids::uuid[])

View File

@@ -391,7 +391,7 @@ INSERT INTO "WorkflowRun" (
$7::uuid,
$8::uuid,
$9::jsonb
) RETURNING "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id, "childIndex", "childKey", "parentId", "parentStepRunId", "additionalMetadata"
) RETURNING "createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id, "childIndex", "childKey", "parentId", "parentStepRunId", "additionalMetadata", duration
`
type CreateWorkflowRunParams struct {
@@ -437,6 +437,7 @@ func (q *Queries) CreateWorkflowRun(ctx context.Context, db DBTX, arg CreateWork
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
)
return &i, err
}
@@ -554,7 +555,7 @@ func (q *Queries) DeleteExpiredWorkflowRuns(ctx context.Context, db DBTX, arg De
const getChildWorkflowRun = `-- name: GetChildWorkflowRun :one
SELECT
"createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id, "childIndex", "childKey", "parentId", "parentStepRunId", "additionalMetadata"
"createdAt", "updatedAt", "deletedAt", "tenantId", "workflowVersionId", status, error, "startedAt", "finishedAt", "concurrencyGroupId", "displayName", id, "childIndex", "childKey", "parentId", "parentStepRunId", "additionalMetadata", duration
FROM
"WorkflowRun"
WHERE
@@ -600,6 +601,7 @@ func (q *Queries) GetChildWorkflowRun(ctx context.Context, db DBTX, arg GetChild
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
)
return &i, err
}
@@ -650,7 +652,7 @@ func (q *Queries) GetScheduledChildWorkflowRun(ctx context.Context, db DBTX, arg
const getWorkflowRun = `-- name: GetWorkflowRun :many
SELECT
runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, runs."childIndex", runs."childKey", runs."parentId", runs."parentStepRunId", runs."additionalMetadata",
runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, runs."childIndex", runs."childKey", runs."parentId", runs."parentStepRunId", runs."additionalMetadata", runs.duration,
runtriggers.id, runtriggers."createdAt", runtriggers."updatedAt", runtriggers."deletedAt", runtriggers."tenantId", runtriggers."eventId", runtriggers."cronParentId", runtriggers."cronSchedule", runtriggers."scheduledId", runtriggers.input, runtriggers."parentId",
workflowversion.id, workflowversion."createdAt", workflowversion."updatedAt", workflowversion."deletedAt", workflowversion.version, workflowversion."order", workflowversion."workflowId", workflowversion.checksum, workflowversion."scheduleTimeout", workflowversion."onFailureJobId",
workflow."name" as "workflowName",
@@ -717,6 +719,7 @@ func (q *Queries) GetWorkflowRun(ctx context.Context, db DBTX, arg GetWorkflowRu
&i.WorkflowRun.ParentId,
&i.WorkflowRun.ParentStepRunId,
&i.WorkflowRun.AdditionalMetadata,
&i.WorkflowRun.Duration,
&i.WorkflowRunTriggeredBy.ID,
&i.WorkflowRunTriggeredBy.CreatedAt,
&i.WorkflowRunTriggeredBy.UpdatedAt,
@@ -832,7 +835,7 @@ func (q *Queries) ListActiveQueuedWorkflowVersions(ctx context.Context, db DBTX)
const listWorkflowRuns = `-- name: ListWorkflowRuns :many
SELECT
runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, runs."childIndex", runs."childKey", runs."parentId", runs."parentStepRunId", runs."additionalMetadata",
runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, runs."childIndex", runs."childKey", runs."parentId", runs."parentStepRunId", runs."additionalMetadata", runs.duration,
workflow.id, workflow."createdAt", workflow."updatedAt", workflow."deletedAt", workflow."tenantId", workflow.name, workflow.description,
runtriggers.id, runtriggers."createdAt", runtriggers."updatedAt", runtriggers."deletedAt", runtriggers."tenantId", runtriggers."eventId", runtriggers."cronParentId", runtriggers."cronSchedule", runtriggers."scheduledId", runtriggers.input, runtriggers."parentId",
workflowversion.id, workflowversion."createdAt", workflowversion."updatedAt", workflowversion."deletedAt", workflowversion.version, workflowversion."order", workflowversion."workflowId", workflowversion.checksum, workflowversion."scheduleTimeout", workflowversion."onFailureJobId",
@@ -896,7 +899,13 @@ WHERE
)
ORDER BY
case when $13 = 'createdAt ASC' THEN runs."createdAt" END ASC ,
case when $13 = 'createdAt DESC' then runs."createdAt" END DESC,
case when $13 = 'createdAt DESC' THEN runs."createdAt" END DESC,
case when $13 = 'finishedAt ASC' THEN runs."finishedAt" END ASC ,
case when $13 = 'finishedAt DESC' THEN runs."finishedAt" END DESC,
case when $13 = 'startedAt ASC' THEN runs."startedAt" END ASC ,
case when $13 = 'startedAt DESC' THEN runs."startedAt" END DESC,
case when $13 = 'duration ASC' THEN runs."duration" END ASC NULLS FIRST,
case when $13 = 'duration DESC' THEN runs."duration" END DESC NULLS LAST,
runs."id" ASC
OFFSET
COALESCE($14, 0)
@@ -976,6 +985,7 @@ func (q *Queries) ListWorkflowRuns(ctx context.Context, db DBTX, arg ListWorkflo
&i.WorkflowRun.ParentId,
&i.WorkflowRun.ParentStepRunId,
&i.WorkflowRun.AdditionalMetadata,
&i.WorkflowRun.Duration,
&i.Workflow.ID,
&i.Workflow.CreatedAt,
&i.Workflow.UpdatedAt,
@@ -1078,7 +1088,7 @@ WHERE
"WorkflowRun".id = eligible_runs.id AND
"WorkflowRun"."status" = 'QUEUED'
RETURNING
"WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata"
"WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata", "WorkflowRun".duration
`
type PopWorkflowRunsRoundRobinParams struct {
@@ -1114,6 +1124,7 @@ func (q *Queries) PopWorkflowRunsRoundRobin(ctx context.Context, db DBTX, arg Po
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
); err != nil {
return nil, err
}
@@ -1155,7 +1166,8 @@ SET "status" = CASE
-- When all job runs have succeeded, then the workflow is succeeded
WHEN j.succeededRuns > 0 AND j.pendingRuns = 0 AND j.runningRuns = 0 AND j.failedRuns = 0 AND j.cancelledRuns = 0 THEN 'SUCCEEDED'
ELSE "status"
END, "finishedAt" = CASE
END,
"finishedAt" = CASE
-- Final states are final, cannot be updated
WHEN "finishedAt" IS NOT NULL THEN "finishedAt"
-- We check for running first, because if a job run is running, then the workflow is not finished
@@ -1163,12 +1175,23 @@ END, "finishedAt" = CASE
-- When one job run has failed or been cancelled, then the workflow is failed
WHEN j.failedRuns > 0 OR j.cancelledRuns > 0 OR j.succeededRuns > 0 THEN NOW()
ELSE "finishedAt"
END, "startedAt" = CASE
END,
"startedAt" = CASE
-- Started at is final, cannot be changed
WHEN "startedAt" IS NOT NULL THEN "startedAt"
-- If a job is running or in a final state, then the workflow has started
WHEN j.runningRuns > 0 OR j.succeededRuns > 0 OR j.failedRuns > 0 OR j.cancelledRuns > 0 THEN NOW()
ELSE "startedAt"
END,
"duration" = CASE
-- duration is final, cannot be changed
WHEN "duration" IS NOT NULL THEN "duration"
-- We check for running first, because if a job run is running, then the workflow is not finished
WHEN j.runningRuns > 0 THEN NULL
-- When one job run has failed or been cancelled, then the workflow is failed
WHEN j.failedRuns > 0 OR j.cancelledRuns > 0 OR j.succeededRuns > 0 THEN
EXTRACT(EPOCH FROM (NOW() - "startedAt")) * 1000
ELSE "duration"
END
FROM
jobRuns j
@@ -1177,7 +1200,7 @@ WHERE "id" = (
FROM "JobRun"
WHERE "id" = $1::uuid
) AND "tenantId" = $2::uuid
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata"
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata", "WorkflowRun".duration
`
type ResolveWorkflowRunStatusParams struct {
@@ -1206,6 +1229,7 @@ func (q *Queries) ResolveWorkflowRunStatus(ctx context.Context, db DBTX, arg Res
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
)
return &i, err
}
@@ -1217,11 +1241,12 @@ SET
"status" = COALESCE($1::"WorkflowRunStatus", "status"),
"error" = COALESCE($2::text, "error"),
"startedAt" = COALESCE($3::timestamp, "startedAt"),
"finishedAt" = COALESCE($4::timestamp, "finishedAt")
"finishedAt" = COALESCE($4::timestamp, "finishedAt"),
"duration" = COALESCE($4::timestamp, "finishedAt") - COALESCE($3::timestamp, "startedAt")
WHERE
"tenantId" = $5::uuid AND
"id" = ANY($6::uuid[])
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata"
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata", "WorkflowRun".duration
`
type UpdateManyWorkflowRunParams struct {
@@ -1267,6 +1292,7 @@ func (q *Queries) UpdateManyWorkflowRun(ctx context.Context, db DBTX, arg Update
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
); err != nil {
return nil, err
}
@@ -1289,11 +1315,14 @@ SET
END,
"error" = COALESCE($2::text, "error"),
"startedAt" = COALESCE($3::timestamp, "startedAt"),
"finishedAt" = COALESCE($4::timestamp, "finishedAt")
"finishedAt" = COALESCE($4::timestamp, "finishedAt"),
"duration" =
EXTRACT(EPOCH FROM (COALESCE($4::timestamp, "finishedAt") - COALESCE($3::timestamp, "startedAt")) * 1000)
WHERE
"id" = $5::uuid AND
"tenantId" = $6::uuid
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata"
RETURNING "WorkflowRun"."createdAt", "WorkflowRun"."updatedAt", "WorkflowRun"."deletedAt", "WorkflowRun"."tenantId", "WorkflowRun"."workflowVersionId", "WorkflowRun".status, "WorkflowRun".error, "WorkflowRun"."startedAt", "WorkflowRun"."finishedAt", "WorkflowRun"."concurrencyGroupId", "WorkflowRun"."displayName", "WorkflowRun".id, "WorkflowRun"."childIndex", "WorkflowRun"."childKey", "WorkflowRun"."parentId", "WorkflowRun"."parentStepRunId", "WorkflowRun"."additionalMetadata", "WorkflowRun".duration
`
type UpdateWorkflowRunParams struct {
@@ -1333,6 +1362,7 @@ func (q *Queries) UpdateWorkflowRun(ctx context.Context, db DBTX, arg UpdateWork
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
)
return &i, err
}
@@ -1353,20 +1383,28 @@ SET "status" = CASE
WHEN groupKeyRun.groupKeyRunStatus IN ('FAILED', 'CANCELLED') THEN 'FAILED'
WHEN groupKeyRun.output IS NOT NULL THEN 'QUEUED'
ELSE "status"
END, "finishedAt" = CASE
END,
"finishedAt" = CASE
-- Final states are final, cannot be updated
WHEN "finishedAt" IS NOT NULL THEN "finishedAt"
-- When one job run has failed or been cancelled, then the workflow is failed
WHEN groupKeyRun.groupKeyRunStatus IN ('FAILED', 'CANCELLED') THEN NOW()
ELSE "finishedAt"
END,
"duration" = CASE
-- duration is final, cannot be changed
WHEN "duration" IS NOT NULL THEN "duration"
WHEN "startedAt" IS NOT NULL AND groupKeyRun.groupKeyRunStatus IN ('FAILED', 'CANCELLED') THEN
EXTRACT(EPOCH FROM (NOW() - "startedAt")) * 1000
ELSE "duration"
END,
"concurrencyGroupId" = groupKeyRun."output"
FROM
groupKeyRun
WHERE
workflowRun."id" = groupKeyRun."workflowRunId" AND
workflowRun."tenantId" = $1::uuid
RETURNING workflowrun."createdAt", workflowrun."updatedAt", workflowrun."deletedAt", workflowrun."tenantId", workflowrun."workflowVersionId", workflowrun.status, workflowrun.error, workflowrun."startedAt", workflowrun."finishedAt", workflowrun."concurrencyGroupId", workflowrun."displayName", workflowrun.id, workflowrun."childIndex", workflowrun."childKey", workflowrun."parentId", workflowrun."parentStepRunId", workflowrun."additionalMetadata"
RETURNING workflowrun."createdAt", workflowrun."updatedAt", workflowrun."deletedAt", workflowrun."tenantId", workflowrun."workflowVersionId", workflowrun.status, workflowrun.error, workflowrun."startedAt", workflowrun."finishedAt", workflowrun."concurrencyGroupId", workflowrun."displayName", workflowrun.id, workflowrun."childIndex", workflowrun."childKey", workflowrun."parentId", workflowrun."parentStepRunId", workflowrun."additionalMetadata", workflowrun.duration
`
type UpdateWorkflowRunGroupKeyParams struct {
@@ -1395,6 +1433,7 @@ func (q *Queries) UpdateWorkflowRunGroupKey(ctx context.Context, db DBTX, arg Up
&i.ParentId,
&i.ParentStepRunId,
&i.AdditionalMetadata,
&i.Duration,
)
return &i, err
}

View File

@@ -988,7 +988,7 @@ func (q *Queries) ListWorkflowsForEvent(ctx context.Context, db DBTX, arg ListWo
const listWorkflowsLatestRuns = `-- name: ListWorkflowsLatestRuns :many
SELECT
DISTINCT ON (workflow."id") runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, runs."childIndex", runs."childKey", runs."parentId", runs."parentStepRunId", runs."additionalMetadata", workflow."id" as "workflowId"
DISTINCT ON (workflow."id") runs."createdAt", runs."updatedAt", runs."deletedAt", runs."tenantId", runs."workflowVersionId", runs.status, runs.error, runs."startedAt", runs."finishedAt", runs."concurrencyGroupId", runs."displayName", runs.id, runs."childIndex", runs."childKey", runs."parentId", runs."parentStepRunId", runs."additionalMetadata", runs.duration, workflow."id" as "workflowId"
FROM
"WorkflowRun" as runs
LEFT JOIN
@@ -1064,6 +1064,7 @@ func (q *Queries) ListWorkflowsLatestRuns(ctx context.Context, db DBTX, arg List
&i.WorkflowRun.ParentId,
&i.WorkflowRun.ParentStepRunId,
&i.WorkflowRun.AdditionalMetadata,
&i.WorkflowRun.Duration,
&i.WorkflowId,
); err != nil {
return nil, err

View File

@@ -261,7 +261,7 @@ type ListWorkflowRunsOpts struct {
Limit *int
// (optional) the order by field
OrderBy *string `validate:"omitempty,oneof=createdAt"`
OrderBy *string `validate:"omitempty,oneof=createdAt finishedAt startedAt duration"`
// (optional) the order direction
OrderDirection *string `validate:"omitempty,oneof=ASC DESC"`

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "WorkflowRun" ADD COLUMN "duration" INTEGER;

View File

@@ -839,6 +839,9 @@ model WorkflowRun {
// the run finished at
finishedAt DateTime?
// the duration of the run (ms)
duration Int?
// a list of dependents for this workflow run
children WorkflowRun[] @relation("WorkflowRunChild")
scheduledChildren WorkflowTriggerScheduledRef[]

View File

@@ -0,0 +1,2 @@
-- Modify "WorkflowRun" table
ALTER TABLE "WorkflowRun" ADD COLUMN "duration" integer NULL;

View File

@@ -1,4 +1,4 @@
h1:Rh/GsNXj7HMJGp47dnyHuPbDUWVgOOqDrE4H980Sq3A=
h1:fc2JeZ5rMJmnCco4GenTzhobz8nIrA/vNMFprROPl1s=
20240115180414_init.sql h1:Ef3ZyjAHkmJPdGF/dEWCahbwgcg6uGJKnDxW2JCRi2k=
20240122014727_v0_6_0.sql h1:o/LdlteAeFgoHJ3e/M4Xnghqt9826IE/Y/h0q95Acuo=
20240126235456_v0_7_0.sql h1:KiVzt/hXgQ6esbdC6OMJOOWuYEXmy1yeCpmsVAHTFKs=
@@ -38,3 +38,4 @@ h1:Rh/GsNXj7HMJGp47dnyHuPbDUWVgOOqDrE4H980Sq3A=
20240703194656_v0.35.1.sql h1:wg/DWVOmWy7UiXrimlnwongTcT0aJa4pYSOYkiREgNg=
20240704211315_v0.35.2.sql h1:/AzVYp+jzwPGx8JHUCPjBi2CnXmFvtsTWL3SgrC49IE=
20240712142946_v0.36.0.sql h1:YA/z+ZRR9QhqF+dCXy1fBgJczSyyaSEFXgThcID6SfI=
20240715154334_v0.37.0.sql h1:/lu8OPyH2rHPJRk3wL+LBsHp698YMyh0wLz+bRu7qXU=

View File

@@ -638,6 +638,7 @@ CREATE TABLE "WorkflowRun" (
"parentId" UUID,
"parentStepRunId" UUID,
"additionalMetadata" JSONB,
"duration" INTEGER,
CONSTRAINT "WorkflowRun_pkey" PRIMARY KEY ("id")
);