@shipfox/api-workflows 10.2.0 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +117 -0
- package/README.md +75 -0
- package/dist/core/agent-defaults.d.ts +2 -1
- package/dist/core/agent-defaults.d.ts.map +1 -1
- package/dist/core/agent-defaults.js.map +1 -1
- package/dist/core/checkout.d.ts +7 -21
- package/dist/core/checkout.d.ts.map +1 -1
- package/dist/core/checkout.js +122 -41
- package/dist/core/checkout.js.map +1 -1
- package/dist/core/entities/job-execution.d.ts +8 -0
- package/dist/core/entities/job-execution.d.ts.map +1 -1
- package/dist/core/entities/job-execution.js +13 -1
- package/dist/core/entities/job-execution.js.map +1 -1
- package/dist/core/entities/job-listener-event.d.ts +2 -0
- package/dist/core/entities/job-listener-event.d.ts.map +1 -1
- package/dist/core/entities/job-listener-event.js.map +1 -1
- package/dist/core/entities/step.d.ts +13 -3
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/entities/step.js +6 -0
- package/dist/core/entities/step.js.map +1 -1
- package/dist/core/entities/workflow-run-attempt.d.ts +1 -0
- package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
- package/dist/core/entities/workflow-run-attempt.js.map +1 -1
- package/dist/core/entities/workflow-run.d.ts +17 -0
- package/dist/core/entities/workflow-run.d.ts.map +1 -1
- package/dist/core/entities/workflow-run.js.map +1 -1
- package/dist/core/errors.d.ts +9 -2
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +10 -5
- package/dist/core/errors.js.map +1 -1
- package/dist/core/job-execution.d.ts.map +1 -1
- package/dist/core/job-execution.js +14 -8
- package/dist/core/job-execution.js.map +1 -1
- package/dist/core/job-transition/decide-job-activation.d.ts +1 -0
- package/dist/core/job-transition/decide-job-activation.d.ts.map +1 -1
- package/dist/core/job-transition/decide-job-activation.js +1 -0
- package/dist/core/job-transition/decide-job-activation.js.map +1 -1
- package/dist/core/job-transition/derive-job-success.d.ts +1 -0
- package/dist/core/job-transition/derive-job-success.d.ts.map +1 -1
- package/dist/core/job-transition/derive-job-success.js +5 -8
- package/dist/core/job-transition/derive-job-success.js.map +1 -1
- package/dist/core/listener-execution-materialization.d.ts +6 -3
- package/dist/core/listener-execution-materialization.d.ts.map +1 -1
- package/dist/core/listener-execution-materialization.js +44 -6
- package/dist/core/listener-execution-materialization.js.map +1 -1
- package/dist/core/resolve-trigger-reference.d.ts +11 -0
- package/dist/core/resolve-trigger-reference.d.ts.map +1 -0
- package/dist/core/resolve-trigger-reference.js +39 -0
- package/dist/core/resolve-trigger-reference.js.map +1 -0
- package/dist/core/run-workflow.d.ts +1 -0
- package/dist/core/run-workflow.d.ts.map +1 -1
- package/dist/core/run-workflow.js +1 -0
- package/dist/core/run-workflow.js.map +1 -1
- package/dist/core/step-config/agent.d.ts +1 -2
- package/dist/core/step-config/agent.d.ts.map +1 -1
- package/dist/core/step-config/agent.js +22 -7
- package/dist/core/step-config/agent.js.map +1 -1
- package/dist/core/step-config/assemble-run-context.d.ts +19 -8
- package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
- package/dist/core/step-config/assemble-run-context.js +51 -19
- package/dist/core/step-config/assemble-run-context.js.map +1 -1
- package/dist/core/step-config/complete-step-dispatch-config.d.ts.map +1 -1
- package/dist/core/step-config/complete-step-dispatch-config.js +72 -4
- package/dist/core/step-config/complete-step-dispatch-config.js.map +1 -1
- package/dist/core/step-config/index.d.ts +1 -0
- package/dist/core/step-config/index.d.ts.map +1 -1
- package/dist/core/step-config/index.js +1 -0
- package/dist/core/step-config/index.js.map +1 -1
- package/dist/core/step-config/materialize-job-execution-steps.d.ts +1 -1
- package/dist/core/step-config/materialize-job-execution-steps.d.ts.map +1 -1
- package/dist/core/step-config/materialize-job-execution-steps.js +49 -8
- package/dist/core/step-config/materialize-job-execution-steps.js.map +1 -1
- package/dist/core/step-config/materialize-workflow-model.d.ts +3 -3
- package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
- package/dist/core/step-config/materialize-workflow-model.js +9 -5
- package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
- package/dist/core/step-config/resolve-job-execution-name.d.ts +3 -3
- package/dist/core/step-config/resolve-job-execution-name.d.ts.map +1 -1
- package/dist/core/step-config/resolve-job-execution-name.js +24 -13
- package/dist/core/step-config/resolve-job-execution-name.js.map +1 -1
- package/dist/core/step-config/resolve-step-config.d.ts.map +1 -1
- package/dist/core/step-config/resolve-step-config.js +174 -9
- package/dist/core/step-config/resolve-step-config.js.map +1 -1
- package/dist/core/step-config/resolve-workflow-run-name.d.ts +19 -0
- package/dist/core/step-config/resolve-workflow-run-name.d.ts.map +1 -0
- package/dist/core/step-config/resolve-workflow-run-name.js +73 -0
- package/dist/core/step-config/resolve-workflow-run-name.js.map +1 -0
- package/dist/core/step-transition/decide-step-transition.js.map +1 -1
- package/dist/core/step-transition/evaluate-gate.d.ts +2 -1
- package/dist/core/step-transition/evaluate-gate.d.ts.map +1 -1
- package/dist/core/step-transition/evaluate-gate.js +5 -3
- package/dist/core/step-transition/evaluate-gate.js.map +1 -1
- package/dist/core/workflow-run-creation.d.ts +3 -0
- package/dist/core/workflow-run-creation.d.ts.map +1 -1
- package/dist/core/workflow-run-creation.js +22 -7
- package/dist/core/workflow-run-creation.js.map +1 -1
- package/dist/db/db.d.ts +278 -10
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +2 -0
- package/dist/db/db.js.map +1 -1
- package/dist/db/index.d.ts +3 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +2 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/job-listener-events.d.ts +2 -0
- package/dist/db/job-listener-events.d.ts.map +1 -1
- package/dist/db/job-listener-events.js +1 -0
- package/dist/db/job-listener-events.js.map +1 -1
- package/dist/db/job-listeners.d.ts +2 -0
- package/dist/db/job-listeners.d.ts.map +1 -1
- package/dist/db/job-listeners.js +81 -21
- package/dist/db/job-listeners.js.map +1 -1
- package/dist/db/schema/job-executions.d.ts +3 -3
- package/dist/db/schema/job-executions.d.ts.map +1 -1
- package/dist/db/schema/job-executions.js +8 -4
- package/dist/db/schema/job-executions.js.map +1 -1
- package/dist/db/schema/job-listener-events.d.ts +20 -0
- package/dist/db/schema/job-listener-events.d.ts.map +1 -1
- package/dist/db/schema/job-listener-events.js +2 -0
- package/dist/db/schema/job-listener-events.js.map +1 -1
- package/dist/db/schema/step-attempts.js +2 -2
- package/dist/db/schema/step-attempts.js.map +1 -1
- package/dist/db/schema/steps.d.ts +4 -2
- package/dist/db/schema/steps.d.ts.map +1 -1
- package/dist/db/schema/steps.js +1 -1
- package/dist/db/schema/steps.js.map +1 -1
- package/dist/db/schema/workflow-run-attempts.d.ts +21 -2
- package/dist/db/schema/workflow-run-attempts.d.ts.map +1 -1
- package/dist/db/schema/workflow-run-attempts.js +2 -0
- package/dist/db/schema/workflow-run-attempts.js.map +1 -1
- package/dist/db/schema/workflow-run-counters.d.ts +43 -0
- package/dist/db/schema/workflow-run-counters.d.ts.map +1 -0
- package/dist/db/schema/workflow-run-counters.js +10 -0
- package/dist/db/schema/workflow-run-counters.js.map +1 -0
- package/dist/db/schema/workflow-runs.d.ts +54 -1
- package/dist/db/schema/workflow-runs.d.ts.map +1 -1
- package/dist/db/schema/workflow-runs.js +10 -2
- package/dist/db/schema/workflow-runs.js.map +1 -1
- package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
- package/dist/db/workflow-runs/job-executions.js +35 -14
- package/dist/db/workflow-runs/job-executions.js.map +1 -1
- package/dist/db/workflow-runs/jobs.d.ts +2 -0
- package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
- package/dist/db/workflow-runs/jobs.js +9 -5
- package/dist/db/workflow-runs/jobs.js.map +1 -1
- package/dist/db/workflow-runs/queries.d.ts +51 -0
- package/dist/db/workflow-runs/queries.d.ts.map +1 -1
- package/dist/db/workflow-runs/queries.js +82 -2
- package/dist/db/workflow-runs/queries.js.map +1 -1
- package/dist/db/workflow-runs/run-create.d.ts +1 -0
- package/dist/db/workflow-runs/run-create.d.ts.map +1 -1
- package/dist/db/workflow-runs/run-create.js +159 -32
- package/dist/db/workflow-runs/run-create.js.map +1 -1
- package/dist/db/workflow-runs/run-rerun.d.ts.map +1 -1
- package/dist/db/workflow-runs/run-rerun.js +13 -5
- package/dist/db/workflow-runs/run-rerun.js.map +1 -1
- package/dist/db/workflow-runs/shared.d.ts +1 -0
- package/dist/db/workflow-runs/shared.d.ts.map +1 -1
- package/dist/db/workflow-runs/shared.js +2 -1
- package/dist/db/workflow-runs/shared.js.map +1 -1
- package/dist/db/workflow-runs/steps.js +3 -3
- package/dist/db/workflow-runs/steps.js.map +1 -1
- package/dist/db/workflow-runs.d.ts +4 -3
- package/dist/db/workflow-runs.d.ts.map +1 -1
- package/dist/db/workflow-runs.js +3 -2
- package/dist/db/workflow-runs.js.map +1 -1
- package/dist/metrics/instance.d.ts +1 -0
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +9 -0
- package/dist/metrics/instance.js.map +1 -1
- package/dist/presentation/dto/checkout-token.d.ts +1 -0
- package/dist/presentation/dto/checkout-token.d.ts.map +1 -1
- package/dist/presentation/dto/checkout-token.js +1 -0
- package/dist/presentation/dto/checkout-token.js.map +1 -1
- package/dist/presentation/dto/index.d.ts +1 -1
- package/dist/presentation/dto/index.d.ts.map +1 -1
- package/dist/presentation/dto/index.js +1 -1
- package/dist/presentation/dto/index.js.map +1 -1
- package/dist/presentation/dto/step.d.ts.map +1 -1
- package/dist/presentation/dto/step.js +2 -2
- package/dist/presentation/dto/step.js.map +1 -1
- package/dist/presentation/dto/workflow-run.d.ts +3 -1
- package/dist/presentation/dto/workflow-run.d.ts.map +1 -1
- package/dist/presentation/dto/workflow-run.js +34 -0
- package/dist/presentation/dto/workflow-run.js.map +1 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +31 -3
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/checkout-token.d.ts +1 -1
- package/dist/presentation/routes/checkout-token.d.ts.map +1 -1
- package/dist/presentation/routes/checkout-token.js +32 -20
- package/dist/presentation/routes/checkout-token.js.map +1 -1
- package/dist/presentation/routes/leased-step.d.ts +2 -0
- package/dist/presentation/routes/leased-step.d.ts.map +1 -1
- package/dist/presentation/routes/leased-step.js +2 -1
- package/dist/presentation/routes/leased-step.js.map +1 -1
- package/dist/presentation/routes/list-runs.d.ts.map +1 -1
- package/dist/presentation/routes/list-runs.js +9 -3
- package/dist/presentation/routes/list-runs.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -0
- package/dist/presentation/routes/project-access.d.ts.map +1 -1
- package/dist/presentation/routes/report-step.d.ts.map +1 -1
- package/dist/presentation/routes/report-step.js +9 -2
- package/dist/presentation/routes/report-step.js.map +1 -1
- package/dist/presentation/routes/require-accessible-run.d.ts.map +1 -1
- package/dist/presentation/routes/require-accessible-run.js +1 -1
- package/dist/presentation/routes/require-accessible-run.js.map +1 -1
- package/dist/presentation/subscribers/on-job-steps-settled.js +1 -1
- package/dist/presentation/subscribers/on-job-steps-settled.js.map +1 -1
- package/dist/presentation/subscribers/on-runner-job-claimed.d.ts.map +1 -1
- package/dist/presentation/subscribers/on-runner-job-claimed.js +21 -0
- package/dist/presentation/subscribers/on-runner-job-claimed.js.map +1 -1
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/index.js +2 -1
- package/dist/temporal/activities/index.js.map +1 -1
- package/dist/temporal/activities/orchestration-activities.d.ts +1 -0
- package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
- package/dist/temporal/activities/orchestration-activities.js.map +1 -1
- package/dist/temporal/constants.d.ts +1 -0
- package/dist/temporal/constants.d.ts.map +1 -1
- package/dist/temporal/constants.js +1 -0
- package/dist/temporal/constants.js.map +1 -1
- package/dist/temporal/index.d.ts +1 -1
- package/dist/temporal/index.d.ts.map +1 -1
- package/dist/temporal/index.js +1 -1
- package/dist/temporal/index.js.map +1 -1
- package/dist/temporal/workflows/index.bundle.js +82 -43
- package/dist/temporal/workflows/index.d.ts +1 -1
- package/dist/temporal/workflows/index.d.ts.map +1 -1
- package/dist/temporal/workflows/index.js +1 -1
- package/dist/temporal/workflows/index.js.map +1 -1
- package/dist/temporal/workflows/job-execution-orchestration.d.ts +5 -0
- package/dist/temporal/workflows/job-execution-orchestration.d.ts.map +1 -1
- package/dist/temporal/workflows/job-execution-orchestration.js +77 -43
- package/dist/temporal/workflows/job-execution-orchestration.js.map +1 -1
- package/dist/temporal/workflows/test-env.d.ts +5 -1
- package/dist/temporal/workflows/test-env.d.ts.map +1 -1
- package/dist/temporal/workflows/test-env.js +32 -11
- package/dist/temporal/workflows/test-env.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0000_initial.sql +14 -2
- package/drizzle/0001_windy_sunfire.sql +1 -0
- package/drizzle/meta/0000_snapshot.json +93 -1
- package/drizzle/meta/0001_snapshot.json +1711 -0
- package/drizzle/meta/_journal.json +2 -2
- package/package.json +21 -21
- package/src/core/agent-defaults.ts +2 -1
- package/src/core/checkout.test.ts +378 -67
- package/src/core/checkout.ts +142 -59
- package/src/core/entities/job-execution.test.ts +21 -0
- package/src/core/entities/job-execution.ts +24 -0
- package/src/core/entities/job-listener-event.ts +3 -0
- package/src/core/entities/step.ts +15 -3
- package/src/core/entities/workflow-run-attempt.ts +1 -0
- package/src/core/entities/workflow-run.ts +16 -0
- package/src/core/errors.ts +21 -7
- package/src/core/job-execution.ts +27 -4
- package/src/core/job-transition/decide-job-activation.test.ts +4 -0
- package/src/core/job-transition/decide-job-activation.ts +2 -0
- package/src/core/job-transition/derive-job-success.test.ts +12 -0
- package/src/core/job-transition/derive-job-success.ts +6 -9
- package/src/core/listener-execution-materialization.test.ts +2 -0
- package/src/core/listener-execution-materialization.ts +57 -11
- package/src/core/resolve-trigger-reference.test.ts +160 -0
- package/src/core/resolve-trigger-reference.ts +53 -0
- package/src/core/run-workflow.ts +2 -0
- package/src/core/step-config/agent.ts +29 -12
- package/src/core/step-config/assemble-run-context.test.ts +149 -6
- package/src/core/step-config/assemble-run-context.ts +87 -25
- package/src/core/step-config/complete-step-dispatch-config.test.ts +125 -2
- package/src/core/step-config/complete-step-dispatch-config.ts +83 -1
- package/src/core/step-config/index.ts +7 -0
- package/src/core/step-config/materialize-job-execution-steps.test.ts +250 -1
- package/src/core/step-config/materialize-job-execution-steps.ts +57 -10
- package/src/core/step-config/materialize-workflow-model.test.ts +212 -4
- package/src/core/step-config/materialize-workflow-model.ts +33 -28
- package/src/core/step-config/resolve-job-execution-name.test.ts +37 -15
- package/src/core/step-config/resolve-job-execution-name.ts +30 -15
- package/src/core/step-config/resolve-step-config.ts +175 -10
- package/src/core/step-config/resolve-workflow-run-name.test.ts +115 -0
- package/src/core/step-config/resolve-workflow-run-name.ts +108 -0
- package/src/core/step-transition/decide-step-transition.ts +2 -2
- package/src/core/step-transition/evaluate-gate.test.ts +8 -0
- package/src/core/step-transition/evaluate-gate.ts +8 -1
- package/src/core/workflow-run-creation.test.ts +7 -4
- package/src/core/workflow-run-creation.ts +13 -7
- package/src/db/db.ts +2 -0
- package/src/db/index.ts +6 -0
- package/src/db/job-listener-events.test.ts +19 -0
- package/src/db/job-listener-events.ts +3 -0
- package/src/db/job-listeners.test.ts +187 -5
- package/src/db/job-listeners.ts +122 -30
- package/src/db/schema/job-executions.ts +12 -5
- package/src/db/schema/job-listener-events.ts +3 -0
- package/src/db/schema/step-attempts.ts +2 -2
- package/src/db/schema/steps.ts +2 -1
- package/src/db/schema/workflow-run-attempts.ts +2 -0
- package/src/db/schema/workflow-run-counters.ts +13 -0
- package/src/db/schema/workflow-runs.ts +11 -2
- package/src/db/workflow-runs/job-executions.ts +37 -15
- package/src/db/workflow-runs/jobs.ts +17 -4
- package/src/db/workflow-runs/queries.test.ts +206 -0
- package/src/db/workflow-runs/queries.ts +146 -2
- package/src/db/workflow-runs/run-create.test.ts +606 -8
- package/src/db/workflow-runs/run-create.ts +185 -40
- package/src/db/workflow-runs/run-rerun.test.ts +61 -2
- package/src/db/workflow-runs/run-rerun.ts +15 -5
- package/src/db/workflow-runs/shared.ts +2 -0
- package/src/db/workflow-runs/steps.ts +3 -3
- package/src/db/workflow-runs.ts +7 -0
- package/src/metrics/instance.ts +14 -0
- package/src/presentation/dto/checkout-token.test.ts +19 -9
- package/src/presentation/dto/checkout-token.ts +2 -1
- package/src/presentation/dto/index.ts +1 -1
- package/src/presentation/dto/job.test.ts +9 -0
- package/src/presentation/dto/step.test.ts +12 -0
- package/src/presentation/dto/step.ts +5 -2
- package/src/presentation/dto/workflow-run.ts +44 -2
- package/src/presentation/inter-module.test.ts +165 -0
- package/src/presentation/inter-module.ts +38 -4
- package/src/presentation/routes/cancel-run.test.ts +1 -1
- package/src/presentation/routes/checkout-token.test.ts +357 -142
- package/src/presentation/routes/checkout-token.ts +56 -26
- package/src/presentation/routes/get-run-aggregates.test.ts +1 -1
- package/src/presentation/routes/get-run.test.ts +29 -1
- package/src/presentation/routes/get-step-secrets.test.ts +7 -2
- package/src/presentation/routes/leased-step.ts +9 -1
- package/src/presentation/routes/list-run-attempts.test.ts +1 -1
- package/src/presentation/routes/list-runs.test.ts +58 -1
- package/src/presentation/routes/list-runs.ts +8 -3
- package/src/presentation/routes/report-step.test.ts +25 -0
- package/src/presentation/routes/report-step.ts +10 -2
- package/src/presentation/routes/require-accessible-run.ts +4 -1
- package/src/presentation/routes/rerun-run.test.ts +1 -1
- package/src/presentation/subscribers/on-job-steps-settled.ts +1 -1
- package/src/presentation/subscribers/on-runner-job-claimed.test.ts +49 -0
- package/src/presentation/subscribers/on-runner-job-claimed.ts +22 -0
- package/src/temporal/activities/index.ts +1 -0
- package/src/temporal/activities/orchestration-activities.ts +1 -0
- package/src/temporal/constants.ts +1 -0
- package/src/temporal/index.ts +1 -0
- package/src/temporal/workflows/index.ts +1 -0
- package/src/temporal/workflows/job-execution-orchestration.test.ts +142 -6
- package/src/temporal/workflows/job-execution-orchestration.ts +99 -50
- package/src/temporal/workflows/run-orchestration.test.ts +1 -1
- package/src/temporal/workflows/test-env.ts +50 -13
- package/test/factories/project.ts +2 -0
- package/test/factories/workflow-model.ts +80 -26
- package/test/factories/workflow-run.ts +4 -1
- package/test/fixtures/agent-inter-module.ts +2 -1
- package/test/fixtures/job-with-steps.ts +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/drizzle/0001_agent_tool_materialization.sql +0 -1
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { WORKFLOW_RUN_JOB_PREVIEW_LIMIT } from '@shipfox/api-workflows-dto';
|
|
1
2
|
import { paginateTimestampIdRows, timestampIdCursorWhere } from '@shipfox/node-drizzle';
|
|
2
3
|
import { and, asc, count, desc, eq, gte, lte, sql } from 'drizzle-orm';
|
|
3
4
|
import { db } from '../db.js';
|
|
@@ -90,6 +91,84 @@ export async function listWorkflowRuns(params) {
|
|
|
90
91
|
filteredTotalCount: totalCount
|
|
91
92
|
};
|
|
92
93
|
}
|
|
94
|
+
/**
|
|
95
|
+
* Jobs for a page of runs, keyed by run id.
|
|
96
|
+
*
|
|
97
|
+
* Issued once per page rather than once per run: the run list is the one surface that needs
|
|
98
|
+
* every run's jobs at once, and a per-row query would put 50 round trips behind it.
|
|
99
|
+
*
|
|
100
|
+
* Both reads are bounded by the page, not by workflow size. A workflow has no job limit and
|
|
101
|
+
* this list polls while runs are active, so returning every job of every row would let one
|
|
102
|
+
* large workflow decide how much the endpoint moves every four seconds. The preview is cut
|
|
103
|
+
* per run in the database, and everything past it is described by a grouped count instead.
|
|
104
|
+
*
|
|
105
|
+
* The attempt comes from the caller's own read rather than from a second look at
|
|
106
|
+
* `current_attempt`. Re-reading it here would let a re-run landing between the queries pair
|
|
107
|
+
* attempt 1's run metadata with attempt 2's jobs, and the row would report a status its strip
|
|
108
|
+
* contradicts.
|
|
109
|
+
*
|
|
110
|
+
* The two reads share one repeatable-read snapshot. They describe the same jobs at the same
|
|
111
|
+
* instant, and the strip combines them into a single glyph row, so under the default
|
|
112
|
+
* read-committed isolation a job settling between the statements would draw a pending glyph
|
|
113
|
+
* beside a summary counting it as failed. Sequential inside one transaction is the cost of
|
|
114
|
+
* that; at a four-second poll the extra round trip does not register.
|
|
115
|
+
*/ export async function listWorkflowRunJobSummaries(runs) {
|
|
116
|
+
const summaries = new Map();
|
|
117
|
+
if (runs.length === 0) return summaries;
|
|
118
|
+
// A row-constructor IN over (run, attempt) so each pair is one lookup on the unique index
|
|
119
|
+
// that already covers those two columns.
|
|
120
|
+
const attemptPairs = sql.join(runs.map((run)=>sql`(${run.id}::uuid, ${run.currentAttempt})`), sql`, `);
|
|
121
|
+
const attemptFilter = sql`(${workflowRunAttempts.workflowRunId}, ${workflowRunAttempts.attempt}) in (${attemptPairs})`;
|
|
122
|
+
const { previewRows, countRows } = await db().transaction(async (tx)=>{
|
|
123
|
+
const ranked = tx.select({
|
|
124
|
+
workflowRunId: workflowRunAttempts.workflowRunId,
|
|
125
|
+
id: jobs.id,
|
|
126
|
+
key: jobs.key,
|
|
127
|
+
name: jobs.name,
|
|
128
|
+
status: jobs.status,
|
|
129
|
+
position: jobs.position,
|
|
130
|
+
rank: sql`row_number() over (partition by ${workflowRunAttempts.workflowRunId} order by ${jobs.position} asc, ${jobs.id} asc)`.as('rank')
|
|
131
|
+
}).from(jobs).innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id)).where(attemptFilter).as('ranked');
|
|
132
|
+
return {
|
|
133
|
+
previewRows: await tx.select({
|
|
134
|
+
workflowRunId: ranked.workflowRunId,
|
|
135
|
+
id: ranked.id,
|
|
136
|
+
key: ranked.key,
|
|
137
|
+
name: ranked.name,
|
|
138
|
+
status: ranked.status,
|
|
139
|
+
position: ranked.position
|
|
140
|
+
}).from(ranked).where(lte(ranked.rank, WORKFLOW_RUN_JOB_PREVIEW_LIMIT)).orderBy(asc(ranked.workflowRunId), asc(ranked.position), asc(ranked.id)),
|
|
141
|
+
countRows: await tx.select({
|
|
142
|
+
workflowRunId: workflowRunAttempts.workflowRunId,
|
|
143
|
+
status: jobs.status,
|
|
144
|
+
count: count()
|
|
145
|
+
}).from(jobs).innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id)).where(attemptFilter).groupBy(workflowRunAttempts.workflowRunId, jobs.status)
|
|
146
|
+
};
|
|
147
|
+
}, {
|
|
148
|
+
isolationLevel: 'repeatable read',
|
|
149
|
+
accessMode: 'read only'
|
|
150
|
+
});
|
|
151
|
+
for (const { workflowRunId, ...summary } of previewRows){
|
|
152
|
+
summaryFor(summaries, workflowRunId).preview.push(summary);
|
|
153
|
+
}
|
|
154
|
+
for (const { workflowRunId, status, count: statusCount } of countRows){
|
|
155
|
+
summaryFor(summaries, workflowRunId).statusCounts.push({
|
|
156
|
+
status,
|
|
157
|
+
count: statusCount
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
return summaries;
|
|
161
|
+
}
|
|
162
|
+
function summaryFor(summaries, workflowRunId) {
|
|
163
|
+
const existing = summaries.get(workflowRunId);
|
|
164
|
+
if (existing) return existing;
|
|
165
|
+
const created = {
|
|
166
|
+
preview: [],
|
|
167
|
+
statusCounts: []
|
|
168
|
+
};
|
|
169
|
+
summaries.set(workflowRunId, created);
|
|
170
|
+
return created;
|
|
171
|
+
}
|
|
93
172
|
export async function listWorkflowRunsByProject(projectId) {
|
|
94
173
|
const result = await listWorkflowRuns({
|
|
95
174
|
projectId,
|
|
@@ -175,6 +254,7 @@ export async function getWorkflowRunDetail(workflowRunId, attempt) {
|
|
|
175
254
|
}
|
|
176
255
|
export async function getJobExecutionDetail(jobExecutionId) {
|
|
177
256
|
const rows = await db().select({
|
|
257
|
+
job: jobs,
|
|
178
258
|
jobExecution: jobExecutions,
|
|
179
259
|
step: steps,
|
|
180
260
|
stepAttempt: stepAttempts
|
|
@@ -182,7 +262,7 @@ export async function getJobExecutionDetail(jobExecutionId) {
|
|
|
182
262
|
const first = rows[0];
|
|
183
263
|
if (!first) return undefined;
|
|
184
264
|
const detail = {
|
|
185
|
-
...toJobExecution(first.jobExecution),
|
|
265
|
+
...toJobExecution(first.jobExecution, first.job.name ?? first.job.key),
|
|
186
266
|
steps: []
|
|
187
267
|
};
|
|
188
268
|
const stepById = new Map();
|
|
@@ -223,7 +303,7 @@ function hydrateWorkflowRunDetail(rows, attempt, latestAttempt) {
|
|
|
223
303
|
let jobExecution = jobExecutionById.get(row.jobExecution.id);
|
|
224
304
|
if (!jobExecution) {
|
|
225
305
|
jobExecution = {
|
|
226
|
-
...toJobExecution(row.jobExecution),
|
|
306
|
+
...toJobExecution(row.jobExecution, row.job.name ?? row.job.key),
|
|
227
307
|
steps: []
|
|
228
308
|
};
|
|
229
309
|
jobExecutionById.set(row.jobExecution.id, jobExecution);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/db/workflow-runs/queries.ts"],"sourcesContent":["import {\n paginateTimestampIdRows,\n type TimestampIdCursor,\n timestampIdCursorWhere,\n} from '@shipfox/node-drizzle';\nimport {and, asc, count, desc, eq, gte, lte, type SQL, sql} from 'drizzle-orm';\nimport type {\n JobExecutionDetail,\n StepDetail,\n WorkflowJobDetail,\n WorkflowRun,\n WorkflowRunDetail,\n WorkflowRunStatus,\n} from '#core/entities/workflow-run.js';\nimport {db} from '../db.js';\nimport {jobExecutions, toJobExecution} from '../schema/job-executions.js';\nimport {jobs, toJob} from '../schema/jobs.js';\nimport {stepAttempts, toStepAttempt} from '../schema/step-attempts.js';\nimport {steps, toStep} from '../schema/steps.js';\nimport {toWorkflowRunAttempt, workflowRunAttempts} from '../schema/workflow-run-attempts.js';\nimport {toWorkflowRun, workflowRuns} from '../schema/workflow-runs.js';\n\nexport type WorkflowRunCursor = TimestampIdCursor;\n\nexport interface WorkflowRunFilters {\n status?: WorkflowRunStatus | undefined;\n definitionId?: string | undefined;\n triggerSource?: string | undefined;\n createdFrom?: Date | undefined;\n createdTo?: Date | undefined;\n}\n\nexport interface ListWorkflowRunsParams {\n projectId: string;\n limit: number;\n cursor?: WorkflowRunCursor | undefined;\n filters?: WorkflowRunFilters | undefined;\n includeTotal?: boolean | undefined;\n}\n\nexport interface ListWorkflowRunsResult {\n runs: WorkflowRun[];\n nextCursor: WorkflowRunCursor | null;\n filteredTotalCount: number | null;\n}\n\nexport interface WorkflowRunAggregates {\n status: Array<{value: WorkflowRunStatus; count: number}>;\n triggerSource: Array<{value: string; count: number}>;\n workflow: Array<{value: string; count: number}>;\n}\n\nexport interface WorkflowJobExecutionDepth {\n runningRuns: number;\n runningJobExecutions: number;\n}\n\nexport interface WorkflowJobExecutionDepthParams {\n workspaceId?: string;\n}\n\nexport async function getWorkflowRunById(id: string): Promise<WorkflowRun | undefined> {\n const rows = await db().select().from(workflowRuns).where(eq(workflowRuns.id, id)).limit(1);\n const row = rows[0];\n if (!row) return undefined;\n return toWorkflowRun(row);\n}\n\nexport async function getWorkflowRunByAttemptId(\n workflowRunAttemptId: string,\n): Promise<WorkflowRun | undefined> {\n const rows = await db()\n .select({run: workflowRuns})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRun(row.run) : undefined;\n}\n\nexport async function getWorkflowRunAttemptById(workflowRunAttemptId: string) {\n const rows = await db()\n .select()\n .from(workflowRunAttempts)\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRunAttempt(row) : undefined;\n}\n\nexport async function listRunAttempts(params: {workflowRunId: string; projectId: string}) {\n return (\n await db()\n .select({\n attempt: workflowRunAttempts,\n })\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .orderBy(asc(workflowRunAttempts.attempt))\n ).map((row) => toWorkflowRunAttempt(row.attempt));\n}\n\nexport async function getLatestAttempt(params: {\n workflowRunId: string;\n projectId: string;\n}): Promise<number> {\n const [row] = await db()\n .select({value: sql<number>`coalesce(max(${workflowRunAttempts.attempt}), 1)`})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .limit(1);\n\n return Number(row?.value ?? 1);\n}\n\nexport function buildWorkflowRunListConditions(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n cursor?: WorkflowRunCursor | undefined;\n omit?: 'status' | 'definitionId' | 'triggerSource' | undefined;\n}): SQL[] {\n const filters = params.filters;\n const conditions: SQL[] = [eq(workflowRuns.projectId, params.projectId)];\n const cursorCondition = timestampIdCursorWhere({\n timestampColumn: workflowRuns.createdAt,\n idColumn: workflowRuns.id,\n cursor: params.cursor,\n });\n if (cursorCondition) conditions.push(cursorCondition);\n if (filters?.status && params.omit !== 'status') {\n conditions.push(eq(workflowRuns.status, filters.status));\n }\n if (filters?.definitionId && params.omit !== 'definitionId') {\n conditions.push(eq(workflowRuns.definitionId, filters.definitionId));\n }\n if (filters?.triggerSource && params.omit !== 'triggerSource') {\n conditions.push(eq(workflowRuns.triggerSource, filters.triggerSource));\n }\n if (filters?.createdFrom) {\n conditions.push(gte(workflowRuns.createdAt, filters.createdFrom));\n }\n if (filters?.createdTo) {\n conditions.push(lte(workflowRuns.createdAt, filters.createdTo));\n }\n return conditions;\n}\n\nexport async function listWorkflowRuns(\n params: ListWorkflowRunsParams,\n): Promise<ListWorkflowRunsResult> {\n const conditions = buildWorkflowRunListConditions(params);\n const rows = await db()\n .select()\n .from(workflowRuns)\n .where(and(...conditions))\n .orderBy(desc(workflowRuns.createdAt), desc(workflowRuns.id))\n .limit(params.limit + 1);\n\n let totalCount: number | null = null;\n if (params.includeTotal) {\n const [{value} = {value: 0}] = await db()\n .select({value: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({projectId: params.projectId, filters: params.filters}),\n ),\n );\n totalCount = value;\n }\n\n const page = paginateTimestampIdRows({rows, limit: params.limit, timestampKey: 'createdAt'});\n\n return {\n runs: page.pageRows.map(toWorkflowRun),\n nextCursor: page.nextCursor,\n filteredTotalCount: totalCount,\n };\n}\n\nexport async function listWorkflowRunsByProject(projectId: string): Promise<WorkflowRun[]> {\n const result = await listWorkflowRuns({projectId, limit: 100});\n return result.runs;\n}\n\nexport async function getWorkflowRunAggregates(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n}): Promise<WorkflowRunAggregates> {\n const [statusRows, triggerRows, workflowRows] = await Promise.all([\n db()\n .select({value: workflowRuns.status, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'status',\n }),\n ),\n )\n .groupBy(workflowRuns.status),\n db()\n .select({value: workflowRuns.triggerSource, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'triggerSource',\n }),\n ),\n )\n .groupBy(workflowRuns.triggerSource),\n db()\n .select({value: workflowRuns.definitionId, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'definitionId',\n }),\n ),\n )\n .groupBy(workflowRuns.definitionId),\n ]);\n\n return {\n status: statusRows,\n triggerSource: triggerRows,\n workflow: workflowRows,\n };\n}\n\nexport async function getWorkflowJobExecutionDepth(\n params: WorkflowJobExecutionDepthParams = {},\n): Promise<WorkflowJobExecutionDepth> {\n const runConditions = [eq(workflowRuns.status, 'running')];\n const jobConditions = [eq(jobExecutions.status, 'running')];\n if (params.workspaceId) {\n runConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n jobConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n }\n\n const [runRows, jobRows] = await Promise.all([\n db()\n .select({value: count()})\n .from(workflowRuns)\n .where(and(...runConditions)),\n db()\n .select({value: count()})\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(and(...jobConditions)),\n ]);\n\n return {\n runningRuns: runRows[0]?.value ?? 0,\n runningJobExecutions: jobRows[0]?.value ?? 0,\n };\n}\n\nexport async function getWorkflowRunDetail(\n workflowRunId: string,\n attempt?: number | undefined,\n): Promise<WorkflowRunDetail | undefined> {\n const [target] = await db()\n .select({run: workflowRuns, attempt: workflowRunAttempts})\n .from(workflowRuns)\n .innerJoin(\n workflowRunAttempts,\n and(\n eq(workflowRunAttempts.workflowRunId, workflowRuns.id),\n eq(workflowRunAttempts.attempt, attempt ?? workflowRuns.currentAttempt),\n ),\n )\n .where(eq(workflowRuns.id, workflowRunId))\n .limit(1);\n if (!target) return undefined;\n\n const latestAttempt = await getLatestAttempt({\n workflowRunId: target.run.id,\n projectId: target.run.projectId,\n });\n\n const rows = await db()\n .select({\n run: workflowRuns,\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(workflowRuns)\n .innerJoin(workflowRunAttempts, eq(workflowRunAttempts.id, target.attempt.id))\n .leftJoin(jobs, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(jobExecutions, eq(jobExecutions.jobId, jobs.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(workflowRuns.id, workflowRunId))\n .orderBy(\n asc(jobs.position),\n asc(jobs.id),\n asc(jobExecutions.sequence),\n asc(jobExecutions.id),\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n return hydrateWorkflowRunDetail(rows, target.attempt, latestAttempt);\n}\n\nexport async function getJobExecutionDetail(\n jobExecutionId: string,\n): Promise<JobExecutionDetail | undefined> {\n const rows = await db()\n .select({\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(jobExecutions.id, jobExecutionId))\n .orderBy(\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: JobExecutionDetail = {...toJobExecution(first.jobExecution), steps: []};\n const stepById = new Map<string, StepDetail>();\n for (const row of rows) {\n if (row.step) {\n const step = getOrCreateStepDetail(stepById, detail.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n }\n\n return detail;\n}\n\nfunction hydrateWorkflowRunDetail(\n rows: {\n run: typeof workflowRuns.$inferSelect;\n job: typeof jobs.$inferSelect | null;\n jobExecution: typeof jobExecutions.$inferSelect | null;\n step: typeof steps.$inferSelect | null;\n stepAttempt: typeof stepAttempts.$inferSelect | null;\n }[],\n attempt: typeof workflowRunAttempts.$inferSelect,\n latestAttempt: number,\n): WorkflowRunDetail | undefined {\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: WorkflowRunDetail = {\n ...toWorkflowRun(first.run),\n runAttempt: toWorkflowRunAttempt(attempt),\n latestAttempt,\n jobs: [],\n };\n const jobById = new Map<string, WorkflowJobDetail>();\n const jobExecutionById = new Map<string, JobExecutionDetail>();\n const stepById = new Map<string, StepDetail>();\n\n for (const row of rows) {\n if (!row.job) continue;\n let job = jobById.get(row.job.id);\n if (!job) {\n job = {...toJob(row.job), jobExecutions: []};\n jobById.set(row.job.id, job);\n detail.jobs.push(job);\n }\n\n if (!row.jobExecution) continue;\n let jobExecution = jobExecutionById.get(row.jobExecution.id);\n if (!jobExecution) {\n jobExecution = {...toJobExecution(row.jobExecution), steps: []};\n jobExecutionById.set(row.jobExecution.id, jobExecution);\n job.jobExecutions.push(jobExecution);\n }\n\n if (!row.step) continue;\n const step = getOrCreateStepDetail(stepById, jobExecution.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n\n return detail;\n}\n\nfunction getOrCreateStepDetail(\n stepById: Map<string, StepDetail>,\n target: StepDetail[],\n row: typeof steps.$inferSelect,\n): StepDetail {\n let step = stepById.get(row.id);\n if (!step) {\n step = {...toStep(row), attempts: []};\n stepById.set(row.id, step);\n target.push(step);\n }\n return step;\n}\n"],"names":["paginateTimestampIdRows","timestampIdCursorWhere","and","asc","count","desc","eq","gte","lte","sql","db","jobExecutions","toJobExecution","jobs","toJob","stepAttempts","toStepAttempt","steps","toStep","toWorkflowRunAttempt","workflowRunAttempts","toWorkflowRun","workflowRuns","getWorkflowRunById","id","rows","select","from","where","limit","row","undefined","getWorkflowRunByAttemptId","workflowRunAttemptId","run","innerJoin","workflowRunId","getWorkflowRunAttemptById","listRunAttempts","params","attempt","projectId","orderBy","map","getLatestAttempt","value","Number","buildWorkflowRunListConditions","filters","conditions","cursorCondition","timestampColumn","createdAt","idColumn","cursor","push","status","omit","definitionId","triggerSource","createdFrom","createdTo","listWorkflowRuns","totalCount","includeTotal","page","timestampKey","runs","pageRows","nextCursor","filteredTotalCount","listWorkflowRunsByProject","result","getWorkflowRunAggregates","statusRows","triggerRows","workflowRows","Promise","all","groupBy","workflow","getWorkflowJobExecutionDepth","runConditions","jobConditions","workspaceId","runRows","jobRows","jobId","runningRuns","runningJobExecutions","getWorkflowRunDetail","target","currentAttempt","latestAttempt","job","jobExecution","step","stepAttempt","leftJoin","jobExecutionId","stepId","position","sequence","executionOrder","hydrateWorkflowRunDetail","getJobExecutionDetail","first","detail","stepById","Map","getOrCreateStepDetail","attempts","runAttempt","jobById","jobExecutionById","get","set"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/db/workflow-runs/queries.ts"],"sourcesContent":["import {WORKFLOW_RUN_JOB_PREVIEW_LIMIT} from '@shipfox/api-workflows-dto';\nimport {\n paginateTimestampIdRows,\n type TimestampIdCursor,\n timestampIdCursorWhere,\n} from '@shipfox/node-drizzle';\nimport {and, asc, count, desc, eq, gte, lte, type SQL, sql} from 'drizzle-orm';\nimport type {JobStatus} from '#core/entities/job.js';\nimport type {\n JobExecutionDetail,\n StepDetail,\n WorkflowJobDetail,\n WorkflowRun,\n WorkflowRunDetail,\n WorkflowRunStatus,\n} from '#core/entities/workflow-run.js';\nimport {db} from '../db.js';\nimport {jobExecutions, toJobExecution} from '../schema/job-executions.js';\nimport {jobs, toJob} from '../schema/jobs.js';\nimport {stepAttempts, toStepAttempt} from '../schema/step-attempts.js';\nimport {steps, toStep} from '../schema/steps.js';\nimport {toWorkflowRunAttempt, workflowRunAttempts} from '../schema/workflow-run-attempts.js';\nimport {toWorkflowRun, workflowRuns} from '../schema/workflow-runs.js';\n\nexport type WorkflowRunCursor = TimestampIdCursor;\n\nexport interface WorkflowRunFilters {\n status?: WorkflowRunStatus | undefined;\n definitionId?: string | undefined;\n triggerSource?: string | undefined;\n createdFrom?: Date | undefined;\n createdTo?: Date | undefined;\n}\n\nexport interface ListWorkflowRunsParams {\n projectId: string;\n limit: number;\n cursor?: WorkflowRunCursor | undefined;\n filters?: WorkflowRunFilters | undefined;\n includeTotal?: boolean | undefined;\n}\n\nexport interface ListWorkflowRunsResult {\n runs: WorkflowRun[];\n nextCursor: WorkflowRunCursor | null;\n filteredTotalCount: number | null;\n}\n\n/** A run-list job glyph: enough to draw and label it, none of its steps. */\nexport interface WorkflowRunJobSummary {\n id: string;\n key: string;\n name: string | null;\n status: JobStatus;\n position: number;\n}\n\nexport interface WorkflowRunAggregates {\n status: Array<{value: WorkflowRunStatus; count: number}>;\n triggerSource: Array<{value: string; count: number}>;\n workflow: Array<{value: string; count: number}>;\n}\n\nexport interface WorkflowJobExecutionDepth {\n runningRuns: number;\n runningJobExecutions: number;\n}\n\nexport interface WorkflowJobExecutionDepthParams {\n workspaceId?: string;\n}\n\nexport async function getWorkflowRunById(id: string): Promise<WorkflowRun | undefined> {\n const rows = await db().select().from(workflowRuns).where(eq(workflowRuns.id, id)).limit(1);\n const row = rows[0];\n if (!row) return undefined;\n return toWorkflowRun(row);\n}\n\nexport async function getWorkflowRunByAttemptId(\n workflowRunAttemptId: string,\n): Promise<WorkflowRun | undefined> {\n const rows = await db()\n .select({run: workflowRuns})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRun(row.run) : undefined;\n}\n\nexport async function getWorkflowRunAttemptById(workflowRunAttemptId: string) {\n const rows = await db()\n .select()\n .from(workflowRunAttempts)\n .where(eq(workflowRunAttempts.id, workflowRunAttemptId))\n .limit(1);\n const row = rows[0];\n return row ? toWorkflowRunAttempt(row) : undefined;\n}\n\nexport async function listRunAttempts(params: {workflowRunId: string; projectId: string}) {\n return (\n await db()\n .select({\n attempt: workflowRunAttempts,\n })\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .orderBy(asc(workflowRunAttempts.attempt))\n ).map((row) => toWorkflowRunAttempt(row.attempt));\n}\n\nexport async function getLatestAttempt(params: {\n workflowRunId: string;\n projectId: string;\n}): Promise<number> {\n const [row] = await db()\n .select({value: sql<number>`coalesce(max(${workflowRunAttempts.attempt}), 1)`})\n .from(workflowRunAttempts)\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(\n and(\n eq(workflowRunAttempts.workflowRunId, params.workflowRunId),\n eq(workflowRuns.projectId, params.projectId),\n ),\n )\n .limit(1);\n\n return Number(row?.value ?? 1);\n}\n\nexport function buildWorkflowRunListConditions(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n cursor?: WorkflowRunCursor | undefined;\n omit?: 'status' | 'definitionId' | 'triggerSource' | undefined;\n}): SQL[] {\n const filters = params.filters;\n const conditions: SQL[] = [eq(workflowRuns.projectId, params.projectId)];\n const cursorCondition = timestampIdCursorWhere({\n timestampColumn: workflowRuns.createdAt,\n idColumn: workflowRuns.id,\n cursor: params.cursor,\n });\n if (cursorCondition) conditions.push(cursorCondition);\n if (filters?.status && params.omit !== 'status') {\n conditions.push(eq(workflowRuns.status, filters.status));\n }\n if (filters?.definitionId && params.omit !== 'definitionId') {\n conditions.push(eq(workflowRuns.definitionId, filters.definitionId));\n }\n if (filters?.triggerSource && params.omit !== 'triggerSource') {\n conditions.push(eq(workflowRuns.triggerSource, filters.triggerSource));\n }\n if (filters?.createdFrom) {\n conditions.push(gte(workflowRuns.createdAt, filters.createdFrom));\n }\n if (filters?.createdTo) {\n conditions.push(lte(workflowRuns.createdAt, filters.createdTo));\n }\n return conditions;\n}\n\nexport async function listWorkflowRuns(\n params: ListWorkflowRunsParams,\n): Promise<ListWorkflowRunsResult> {\n const conditions = buildWorkflowRunListConditions(params);\n const rows = await db()\n .select()\n .from(workflowRuns)\n .where(and(...conditions))\n .orderBy(desc(workflowRuns.createdAt), desc(workflowRuns.id))\n .limit(params.limit + 1);\n\n let totalCount: number | null = null;\n if (params.includeTotal) {\n const [{value} = {value: 0}] = await db()\n .select({value: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({projectId: params.projectId, filters: params.filters}),\n ),\n );\n totalCount = value;\n }\n\n const page = paginateTimestampIdRows({rows, limit: params.limit, timestampKey: 'createdAt'});\n\n return {\n runs: page.pageRows.map(toWorkflowRun),\n nextCursor: page.nextCursor,\n filteredTotalCount: totalCount,\n };\n}\n\n/** The run whose jobs to fetch, pinned to the attempt the caller already read. */\nexport interface WorkflowRunJobSummaryTarget {\n id: string;\n currentAttempt: number;\n}\n\n/**\n * A page row's jobs: a bounded slice to draw, and totals describing all of them.\n *\n * The preview is what a row can show; `statusCounts` is what it can say. Keeping the counts\n * server-side is what lets a row report a failure that sits past the preview.\n */\nexport interface WorkflowRunJobsSummary {\n preview: WorkflowRunJobSummary[];\n statusCounts: WorkflowRunJobStatusCount[];\n}\n\nexport interface WorkflowRunJobStatusCount {\n status: JobStatus;\n count: number;\n}\n\n/**\n * Jobs for a page of runs, keyed by run id.\n *\n * Issued once per page rather than once per run: the run list is the one surface that needs\n * every run's jobs at once, and a per-row query would put 50 round trips behind it.\n *\n * Both reads are bounded by the page, not by workflow size. A workflow has no job limit and\n * this list polls while runs are active, so returning every job of every row would let one\n * large workflow decide how much the endpoint moves every four seconds. The preview is cut\n * per run in the database, and everything past it is described by a grouped count instead.\n *\n * The attempt comes from the caller's own read rather than from a second look at\n * `current_attempt`. Re-reading it here would let a re-run landing between the queries pair\n * attempt 1's run metadata with attempt 2's jobs, and the row would report a status its strip\n * contradicts.\n *\n * The two reads share one repeatable-read snapshot. They describe the same jobs at the same\n * instant, and the strip combines them into a single glyph row, so under the default\n * read-committed isolation a job settling between the statements would draw a pending glyph\n * beside a summary counting it as failed. Sequential inside one transaction is the cost of\n * that; at a four-second poll the extra round trip does not register.\n */\nexport async function listWorkflowRunJobSummaries(\n runs: readonly WorkflowRunJobSummaryTarget[],\n): Promise<Map<string, WorkflowRunJobsSummary>> {\n const summaries = new Map<string, WorkflowRunJobsSummary>();\n if (runs.length === 0) return summaries;\n\n // A row-constructor IN over (run, attempt) so each pair is one lookup on the unique index\n // that already covers those two columns.\n const attemptPairs = sql.join(\n runs.map((run) => sql`(${run.id}::uuid, ${run.currentAttempt})`),\n sql`, `,\n );\n const attemptFilter = sql`(${workflowRunAttempts.workflowRunId}, ${workflowRunAttempts.attempt}) in (${attemptPairs})`;\n\n const {previewRows, countRows} = await db().transaction(\n async (tx) => {\n const ranked = tx\n .select({\n workflowRunId: workflowRunAttempts.workflowRunId,\n id: jobs.id,\n key: jobs.key,\n name: jobs.name,\n status: jobs.status,\n position: jobs.position,\n rank: sql<number>`row_number() over (partition by ${workflowRunAttempts.workflowRunId} order by ${jobs.position} asc, ${jobs.id} asc)`.as(\n 'rank',\n ),\n })\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .where(attemptFilter)\n .as('ranked');\n\n return {\n previewRows: await tx\n .select({\n workflowRunId: ranked.workflowRunId,\n id: ranked.id,\n key: ranked.key,\n name: ranked.name,\n status: ranked.status,\n position: ranked.position,\n })\n .from(ranked)\n .where(lte(ranked.rank, WORKFLOW_RUN_JOB_PREVIEW_LIMIT))\n .orderBy(asc(ranked.workflowRunId), asc(ranked.position), asc(ranked.id)),\n countRows: await tx\n .select({\n workflowRunId: workflowRunAttempts.workflowRunId,\n status: jobs.status,\n count: count(),\n })\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .where(attemptFilter)\n .groupBy(workflowRunAttempts.workflowRunId, jobs.status),\n };\n },\n {isolationLevel: 'repeatable read', accessMode: 'read only'},\n );\n\n for (const {workflowRunId, ...summary} of previewRows) {\n summaryFor(summaries, workflowRunId).preview.push(summary);\n }\n for (const {workflowRunId, status, count: statusCount} of countRows) {\n summaryFor(summaries, workflowRunId).statusCounts.push({status, count: statusCount});\n }\n\n return summaries;\n}\n\nfunction summaryFor(\n summaries: Map<string, WorkflowRunJobsSummary>,\n workflowRunId: string,\n): WorkflowRunJobsSummary {\n const existing = summaries.get(workflowRunId);\n if (existing) return existing;\n const created: WorkflowRunJobsSummary = {preview: [], statusCounts: []};\n summaries.set(workflowRunId, created);\n return created;\n}\n\nexport async function listWorkflowRunsByProject(projectId: string): Promise<WorkflowRun[]> {\n const result = await listWorkflowRuns({projectId, limit: 100});\n return result.runs;\n}\n\nexport async function getWorkflowRunAggregates(params: {\n projectId: string;\n filters?: WorkflowRunFilters | undefined;\n}): Promise<WorkflowRunAggregates> {\n const [statusRows, triggerRows, workflowRows] = await Promise.all([\n db()\n .select({value: workflowRuns.status, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'status',\n }),\n ),\n )\n .groupBy(workflowRuns.status),\n db()\n .select({value: workflowRuns.triggerSource, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'triggerSource',\n }),\n ),\n )\n .groupBy(workflowRuns.triggerSource),\n db()\n .select({value: workflowRuns.definitionId, count: count()})\n .from(workflowRuns)\n .where(\n and(\n ...buildWorkflowRunListConditions({\n projectId: params.projectId,\n filters: params.filters,\n omit: 'definitionId',\n }),\n ),\n )\n .groupBy(workflowRuns.definitionId),\n ]);\n\n return {\n status: statusRows,\n triggerSource: triggerRows,\n workflow: workflowRows,\n };\n}\n\nexport async function getWorkflowJobExecutionDepth(\n params: WorkflowJobExecutionDepthParams = {},\n): Promise<WorkflowJobExecutionDepth> {\n const runConditions = [eq(workflowRuns.status, 'running')];\n const jobConditions = [eq(jobExecutions.status, 'running')];\n if (params.workspaceId) {\n runConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n jobConditions.push(eq(workflowRuns.workspaceId, params.workspaceId));\n }\n\n const [runRows, jobRows] = await Promise.all([\n db()\n .select({value: count()})\n .from(workflowRuns)\n .where(and(...runConditions)),\n db()\n .select({value: count()})\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(and(...jobConditions)),\n ]);\n\n return {\n runningRuns: runRows[0]?.value ?? 0,\n runningJobExecutions: jobRows[0]?.value ?? 0,\n };\n}\n\nexport async function getWorkflowRunDetail(\n workflowRunId: string,\n attempt?: number | undefined,\n): Promise<WorkflowRunDetail | undefined> {\n const [target] = await db()\n .select({run: workflowRuns, attempt: workflowRunAttempts})\n .from(workflowRuns)\n .innerJoin(\n workflowRunAttempts,\n and(\n eq(workflowRunAttempts.workflowRunId, workflowRuns.id),\n eq(workflowRunAttempts.attempt, attempt ?? workflowRuns.currentAttempt),\n ),\n )\n .where(eq(workflowRuns.id, workflowRunId))\n .limit(1);\n if (!target) return undefined;\n\n const latestAttempt = await getLatestAttempt({\n workflowRunId: target.run.id,\n projectId: target.run.projectId,\n });\n\n const rows = await db()\n .select({\n run: workflowRuns,\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(workflowRuns)\n .innerJoin(workflowRunAttempts, eq(workflowRunAttempts.id, target.attempt.id))\n .leftJoin(jobs, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .leftJoin(jobExecutions, eq(jobExecutions.jobId, jobs.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(workflowRuns.id, workflowRunId))\n .orderBy(\n asc(jobs.position),\n asc(jobs.id),\n asc(jobExecutions.sequence),\n asc(jobExecutions.id),\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n return hydrateWorkflowRunDetail(rows, target.attempt, latestAttempt);\n}\n\nexport async function getJobExecutionDetail(\n jobExecutionId: string,\n): Promise<JobExecutionDetail | undefined> {\n const rows = await db()\n .select({\n job: jobs,\n jobExecution: jobExecutions,\n step: steps,\n stepAttempt: stepAttempts,\n })\n .from(jobExecutions)\n .innerJoin(jobs, eq(jobExecutions.jobId, jobs.id))\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .leftJoin(steps, eq(steps.jobExecutionId, jobExecutions.id))\n .leftJoin(stepAttempts, eq(stepAttempts.stepId, steps.id))\n .where(eq(jobExecutions.id, jobExecutionId))\n .orderBy(\n asc(steps.position),\n asc(steps.id),\n asc(stepAttempts.executionOrder),\n asc(stepAttempts.id),\n );\n\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: JobExecutionDetail = {\n ...toJobExecution(first.jobExecution, first.job.name ?? first.job.key),\n steps: [],\n };\n const stepById = new Map<string, StepDetail>();\n for (const row of rows) {\n if (row.step) {\n const step = getOrCreateStepDetail(stepById, detail.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n }\n\n return detail;\n}\n\nfunction hydrateWorkflowRunDetail(\n rows: {\n run: typeof workflowRuns.$inferSelect;\n job: typeof jobs.$inferSelect | null;\n jobExecution: typeof jobExecutions.$inferSelect | null;\n step: typeof steps.$inferSelect | null;\n stepAttempt: typeof stepAttempts.$inferSelect | null;\n }[],\n attempt: typeof workflowRunAttempts.$inferSelect,\n latestAttempt: number,\n): WorkflowRunDetail | undefined {\n const first = rows[0];\n if (!first) return undefined;\n\n const detail: WorkflowRunDetail = {\n ...toWorkflowRun(first.run),\n runAttempt: toWorkflowRunAttempt(attempt),\n latestAttempt,\n jobs: [],\n };\n const jobById = new Map<string, WorkflowJobDetail>();\n const jobExecutionById = new Map<string, JobExecutionDetail>();\n const stepById = new Map<string, StepDetail>();\n\n for (const row of rows) {\n if (!row.job) continue;\n let job = jobById.get(row.job.id);\n if (!job) {\n job = {...toJob(row.job), jobExecutions: []};\n jobById.set(row.job.id, job);\n detail.jobs.push(job);\n }\n\n if (!row.jobExecution) continue;\n let jobExecution = jobExecutionById.get(row.jobExecution.id);\n if (!jobExecution) {\n jobExecution = {\n ...toJobExecution(row.jobExecution, row.job.name ?? row.job.key),\n steps: [],\n };\n jobExecutionById.set(row.jobExecution.id, jobExecution);\n job.jobExecutions.push(jobExecution);\n }\n\n if (!row.step) continue;\n const step = getOrCreateStepDetail(stepById, jobExecution.steps, row.step);\n if (row.stepAttempt) {\n step.attempts.push(toStepAttempt(row.stepAttempt));\n }\n }\n\n return detail;\n}\n\nfunction getOrCreateStepDetail(\n stepById: Map<string, StepDetail>,\n target: StepDetail[],\n row: typeof steps.$inferSelect,\n): StepDetail {\n let step = stepById.get(row.id);\n if (!step) {\n step = {...toStep(row), attempts: []};\n stepById.set(row.id, step);\n target.push(step);\n }\n return step;\n}\n"],"names":["WORKFLOW_RUN_JOB_PREVIEW_LIMIT","paginateTimestampIdRows","timestampIdCursorWhere","and","asc","count","desc","eq","gte","lte","sql","db","jobExecutions","toJobExecution","jobs","toJob","stepAttempts","toStepAttempt","steps","toStep","toWorkflowRunAttempt","workflowRunAttempts","toWorkflowRun","workflowRuns","getWorkflowRunById","id","rows","select","from","where","limit","row","undefined","getWorkflowRunByAttemptId","workflowRunAttemptId","run","innerJoin","workflowRunId","getWorkflowRunAttemptById","listRunAttempts","params","attempt","projectId","orderBy","map","getLatestAttempt","value","Number","buildWorkflowRunListConditions","filters","conditions","cursorCondition","timestampColumn","createdAt","idColumn","cursor","push","status","omit","definitionId","triggerSource","createdFrom","createdTo","listWorkflowRuns","totalCount","includeTotal","page","timestampKey","runs","pageRows","nextCursor","filteredTotalCount","listWorkflowRunJobSummaries","summaries","Map","length","attemptPairs","join","currentAttempt","attemptFilter","previewRows","countRows","transaction","tx","ranked","key","name","position","rank","as","groupBy","isolationLevel","accessMode","summary","summaryFor","preview","statusCount","statusCounts","existing","get","created","set","listWorkflowRunsByProject","result","getWorkflowRunAggregates","statusRows","triggerRows","workflowRows","Promise","all","workflow","getWorkflowJobExecutionDepth","runConditions","jobConditions","workspaceId","runRows","jobRows","jobId","runningRuns","runningJobExecutions","getWorkflowRunDetail","target","latestAttempt","job","jobExecution","step","stepAttempt","leftJoin","jobExecutionId","stepId","sequence","executionOrder","hydrateWorkflowRunDetail","getJobExecutionDetail","first","detail","stepById","getOrCreateStepDetail","attempts","runAttempt","jobById","jobExecutionById"],"mappings":"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"}
|
|
@@ -19,6 +19,7 @@ export interface CreateWorkflowRunParams {
|
|
|
19
19
|
name?: string | undefined;
|
|
20
20
|
model: WorkflowModel;
|
|
21
21
|
triggerPayload: TriggerPayload;
|
|
22
|
+
triggerConnectionId?: string | undefined;
|
|
22
23
|
inputs?: Record<string, unknown> | undefined;
|
|
23
24
|
sourceSnapshot?: WorkflowSourceSnapshot | null | undefined;
|
|
24
25
|
triggerIdempotencyKey?: string | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-create.d.ts","sourceRoot":"","sources":["../../../src/db/workflow-runs/run-create.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"run-create.d.ts","sourceRoot":"","sources":["../../../src/db/workflow-runs/run-create.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,aAAa,EACnB,MAAM,8BAA8B,CAAC;AACtC,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,gDAAgD,CAAC;AAC7F,OAAO,KAAK,EAAC,oBAAoB,EAAC,MAAM,wCAAwC,CAAC;AACjF,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AAQpF,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAKnE,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,sBAAsB,EACvB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAC,8BAA8B,EAAC,MAAM,iBAAiB,CAAC;AAoB/D,MAAM,MAAM,gBAAgB,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,8BAA8B,CAAC,OAAO,CAAC,CAAC;IACxD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC;AAED,MAAM,WAAW,uBAAuB;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,KAAK,EAAE,aAAa,CAAC;IACrB,cAAc,EAAE,cAAc,CAAC;IAC/B,mBAAmB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC7C,cAAc,CAAC,EAAE,sBAAsB,GAAG,IAAI,GAAG,SAAS,CAAC;IAC3D,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,oBAAoB,CAAC,EAAE,qBAAqB,GAAG,SAAS,CAAC;IACzD,OAAO,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;IAChF,YAAY,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,EAAE,oBAAoB,GAAG,SAAS,CAAC;CAC7C;AAED,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,CAAC,CAqM7F;AAeD,wBAAsB,uBAAuB,CAAC,MAAM,EAAE;IACpD,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,gBAAgB,EAAE,GAAG,SAAS,CAAC;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,wBAAwB,EAAE,yBAAyB,CAAC,GAAG,SAAS,CAAC;CAC1F,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC,CAkC9C"}
|
|
@@ -1,16 +1,28 @@
|
|
|
1
|
-
import { createWorkflowModelSnapshot } from '@shipfox/api-definitions-dto';
|
|
1
|
+
import { createWorkflowModelSnapshot, WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS } from '@shipfox/api-definitions-dto';
|
|
2
2
|
import { analyzeContextKeyAccess } from '@shipfox/expression';
|
|
3
3
|
import { logger } from '@shipfox/node-opentelemetry';
|
|
4
|
-
import { eq } from 'drizzle-orm';
|
|
4
|
+
import { eq, sql } from 'drizzle-orm';
|
|
5
5
|
import { createAgentToolMaterializationSnapshot, loadAgentToolMaterializationContext } from '#core/agent-tools.js';
|
|
6
6
|
import { InterpolationUnresolvableError } from '#core/errors.js';
|
|
7
|
+
import { resolveWorkflowRunTriggerReference } from '#core/resolve-trigger-reference.js';
|
|
8
|
+
import { assembleCreationContext } from '#core/step-config/assemble-run-context.js';
|
|
9
|
+
import { resolveWorkflowRunName } from '#core/step-config/resolve-workflow-run-name.js';
|
|
7
10
|
import { deriveInitialJobExecutionPlan, materializeWorkflowRunJobs } from '#core/workflow-run-creation.js';
|
|
8
|
-
import { recordWorkflowRunCreated } from '#metrics/instance.js';
|
|
11
|
+
import { recordWorkflowDisplayNameResolutionDegraded, recordWorkflowRunCreated } from '#metrics/instance.js';
|
|
9
12
|
import { db } from '../db.js';
|
|
10
13
|
import { workflowRunAttempts } from '../schema/workflow-run-attempts.js';
|
|
14
|
+
import { workflowRunCounters } from '../schema/workflow-run-counters.js';
|
|
11
15
|
import { toWorkflowRun, workflowRuns } from '../schema/workflow-runs.js';
|
|
12
16
|
import { persistMaterializedRunGraph } from './run-graph.js';
|
|
13
17
|
export async function createWorkflowRun(params) {
|
|
18
|
+
const triggerReference = await resolveWorkflowRunTriggerReference({
|
|
19
|
+
workspaceId: params.workspaceId,
|
|
20
|
+
triggerConnectionId: params.triggerConnectionId,
|
|
21
|
+
triggerPayload: params.triggerPayload,
|
|
22
|
+
integrations: params.integrations,
|
|
23
|
+
projects: params.projects
|
|
24
|
+
});
|
|
25
|
+
const staticName = params.name ?? params.model.name;
|
|
14
26
|
const agentToolContext = params.integrations === undefined ? undefined : await loadAgentToolMaterializationContext({
|
|
15
27
|
model: params.model,
|
|
16
28
|
workspaceId: params.workspaceId,
|
|
@@ -23,17 +35,35 @@ export async function createWorkflowRun(params) {
|
|
|
23
35
|
context: agentToolContext
|
|
24
36
|
});
|
|
25
37
|
const result = await db().transaction(async (tx)=>{
|
|
38
|
+
// Serialize idempotent trigger resolution separately from per-definition number
|
|
39
|
+
// allocation so a replay never consumes a number, including when two deliveries
|
|
40
|
+
// race before either run is visible.
|
|
41
|
+
if (params.triggerIdempotencyKey) {
|
|
42
|
+
await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.triggerIdempotencyKey}))`);
|
|
43
|
+
const existing = await tx.select().from(workflowRuns).where(eq(workflowRuns.triggerIdempotencyKey, params.triggerIdempotencyKey)).limit(1);
|
|
44
|
+
const existingRow = existing[0];
|
|
45
|
+
if (existingRow) return {
|
|
46
|
+
run: toWorkflowRun(existingRow),
|
|
47
|
+
created: false
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// Keep allocation on the existing transaction so a trigger burst cannot pin
|
|
51
|
+
// every pool connection and then wait for a second connection per run.
|
|
52
|
+
const number = await allocateWorkflowRunNumber(tx, params.definitionId);
|
|
26
53
|
const insertResult = await tx.insert(workflowRuns).values({
|
|
27
54
|
workspaceId: params.workspaceId,
|
|
28
55
|
projectId: params.projectId,
|
|
29
56
|
definitionId: params.definitionId,
|
|
30
|
-
|
|
57
|
+
number,
|
|
58
|
+
name: null,
|
|
59
|
+
workflowName: staticName,
|
|
31
60
|
status: 'pending',
|
|
32
61
|
currentAttempt: 1,
|
|
33
62
|
triggerProvider: params.triggerPayload.provider ?? null,
|
|
34
63
|
triggerSource: params.triggerPayload.source,
|
|
35
64
|
triggerEvent: params.triggerPayload.event,
|
|
36
65
|
triggerPayload: params.triggerPayload,
|
|
66
|
+
triggerReference,
|
|
37
67
|
inputs: params.inputs ?? null,
|
|
38
68
|
sourceSnapshot: params.sourceSnapshot ?? null,
|
|
39
69
|
triggerIdempotencyKey: params.triggerIdempotencyKey ?? null
|
|
@@ -56,18 +86,12 @@ export async function createWorkflowRun(params) {
|
|
|
56
86
|
created: false
|
|
57
87
|
};
|
|
58
88
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
agentToolMaterialization
|
|
66
|
-
}).returning();
|
|
67
|
-
if (!attemptRow) throw new Error('Insert returned no rows');
|
|
68
|
-
// Resolving one-shot templates here gives interpolation access to the inserted run id.
|
|
69
|
-
// If resolution fails, the transaction rolls back the run, jobs, steps, and outbox event together.
|
|
70
|
-
// Listening steps are resolved later when a job execution is created.
|
|
89
|
+
// Resolving run-creation templates and predicates here gives them a stable variable snapshot
|
|
90
|
+
// and interpolation access to the inserted run id. Run-name resolution is display-only and
|
|
91
|
+
// persists only a resolved override. If resolution fails, the transaction rolls back the run,
|
|
92
|
+
// jobs, steps, and outbox event together. Listening steps are resolved later when a job
|
|
93
|
+
// execution is created.
|
|
94
|
+
const provisionalRun = toWorkflowRun(runRow);
|
|
71
95
|
const oneShotJobs = params.model.jobs.filter((job)=>job.mode !== 'listening');
|
|
72
96
|
const vars = await loadReferencedVariables({
|
|
73
97
|
model: params.model,
|
|
@@ -77,6 +101,30 @@ export async function createWorkflowRun(params) {
|
|
|
77
101
|
definitionId: params.definitionId,
|
|
78
102
|
secrets: params.secrets
|
|
79
103
|
});
|
|
104
|
+
const runNameResolution = resolveWorkflowRunName({
|
|
105
|
+
runName: params.model.runName,
|
|
106
|
+
context: assembleCreationContext({
|
|
107
|
+
run: provisionalRun,
|
|
108
|
+
triggerPayload: params.triggerPayload,
|
|
109
|
+
inputs: params.inputs ?? null,
|
|
110
|
+
vars
|
|
111
|
+
}).values
|
|
112
|
+
});
|
|
113
|
+
const [resolvedRunRow] = await tx.update(workflowRuns).set({
|
|
114
|
+
name: runNameResolution.value,
|
|
115
|
+
updatedAt: new Date()
|
|
116
|
+
}).where(eq(workflowRuns.id, provisionalRun.id)).returning();
|
|
117
|
+
if (!resolvedRunRow) throw new Error(`Workflow run missing after name resolution: ${runRow.id}`);
|
|
118
|
+
const run = toWorkflowRun(resolvedRunRow);
|
|
119
|
+
const [attemptRow] = await tx.insert(workflowRunAttempts).values({
|
|
120
|
+
workflowRunId: runRow.id,
|
|
121
|
+
attempt: 1,
|
|
122
|
+
status: 'pending',
|
|
123
|
+
model: createWorkflowModelSnapshot(params.model),
|
|
124
|
+
vars,
|
|
125
|
+
agentToolMaterialization
|
|
126
|
+
}).returning();
|
|
127
|
+
if (!attemptRow) throw new Error('Insert returned no rows');
|
|
80
128
|
const materializedJobs = await materializeWorkflowRunJobs({
|
|
81
129
|
run,
|
|
82
130
|
model: params.model,
|
|
@@ -109,27 +157,65 @@ export async function createWorkflowRun(params) {
|
|
|
109
157
|
});
|
|
110
158
|
return {
|
|
111
159
|
run,
|
|
112
|
-
created: true
|
|
160
|
+
created: true,
|
|
161
|
+
nameDegradation: runNameResolution.degradation
|
|
113
162
|
};
|
|
114
163
|
});
|
|
115
|
-
if (result.created
|
|
164
|
+
if (result.created && result.nameDegradation !== undefined) {
|
|
165
|
+
recordWorkflowDisplayNameResolutionDegraded('workflow.run_name', result.nameDegradation.cause);
|
|
166
|
+
logger().warn({
|
|
167
|
+
workflowRunId: result.run.id,
|
|
168
|
+
definitionId: result.run.definitionId,
|
|
169
|
+
field: 'workflow.run_name',
|
|
170
|
+
cause: result.nameDegradation.cause,
|
|
171
|
+
...result.nameDegradation.expression === undefined ? {} : {
|
|
172
|
+
expression: result.nameDegradation.expression.slice(0, 256)
|
|
173
|
+
}
|
|
174
|
+
}, 'Workflow run name resolution degraded to the static workflow name');
|
|
175
|
+
}
|
|
176
|
+
if (result.created) {
|
|
177
|
+
recordWorkflowRunCreated(result.run.triggerPayload.provider ?? result.run.triggerSource);
|
|
178
|
+
}
|
|
116
179
|
return result.run;
|
|
117
180
|
}
|
|
181
|
+
async function allocateWorkflowRunNumber(tx, definitionId) {
|
|
182
|
+
const [counterRow] = await tx.insert(workflowRunCounters).values({
|
|
183
|
+
definitionId,
|
|
184
|
+
nextNumber: 2
|
|
185
|
+
}).onConflictDoUpdate({
|
|
186
|
+
target: workflowRunCounters.definitionId,
|
|
187
|
+
set: {
|
|
188
|
+
nextNumber: sql`${workflowRunCounters.nextNumber} + 1`
|
|
189
|
+
}
|
|
190
|
+
}).returning({
|
|
191
|
+
number: sql`${workflowRunCounters.nextNumber} - 1`
|
|
192
|
+
});
|
|
193
|
+
if (!counterRow) throw new Error('Run counter allocation returned no rows');
|
|
194
|
+
return counterRow.number;
|
|
195
|
+
}
|
|
118
196
|
export async function loadReferencedVariables(params) {
|
|
119
197
|
const references = referencedVariables(params.model, params.jobs ?? params.model.jobs);
|
|
120
198
|
const keys = [
|
|
121
199
|
...new Set(references.map((reference)=>reference.key))
|
|
122
200
|
].sort();
|
|
123
201
|
if (keys.length === 0) return undefined;
|
|
124
|
-
|
|
202
|
+
const requiresSecrets = (reference)=>reference.field !== 'job.execution_name' && reference.field !== 'workflow.run_name';
|
|
203
|
+
const requiredReferences = references.filter(requiresSecrets);
|
|
204
|
+
const requiredKeys = new Set(requiredReferences.map((reference)=>reference.key));
|
|
205
|
+
if (!params.secrets) {
|
|
206
|
+
if (requiredKeys.size === 0) return undefined;
|
|
207
|
+
throw new Error('Secrets client is not configured.');
|
|
208
|
+
}
|
|
125
209
|
const { values: vars } = await params.secrets.getVariablesByNamespace({
|
|
126
210
|
workspaceId: params.workspaceId,
|
|
127
211
|
projectId: params.projectId,
|
|
128
212
|
namespace: ''
|
|
129
213
|
});
|
|
130
|
-
const missingKey =
|
|
214
|
+
const missingKey = [
|
|
215
|
+
...requiredKeys
|
|
216
|
+
].find((key)=>!(key in vars));
|
|
131
217
|
if (missingKey !== undefined) {
|
|
132
|
-
const reference =
|
|
218
|
+
const reference = requiredReferences.find((candidate)=>candidate.key === missingKey);
|
|
133
219
|
throw new InterpolationUnresolvableError(params.definitionId, {
|
|
134
220
|
field: reference?.field ?? 'env',
|
|
135
221
|
source: reference?.source ?? `vars.${missingKey}`,
|
|
@@ -138,14 +224,19 @@ export async function loadReferencedVariables(params) {
|
|
|
138
224
|
}
|
|
139
225
|
});
|
|
140
226
|
}
|
|
141
|
-
|
|
227
|
+
const referencedVars = {};
|
|
228
|
+
for (const key of keys){
|
|
229
|
+
const value = vars[key];
|
|
230
|
+
if (value !== undefined) referencedVars[key] = value;
|
|
231
|
+
}
|
|
232
|
+
return referencedVars;
|
|
142
233
|
}
|
|
143
234
|
function materializeRunGraphJobs(params) {
|
|
144
235
|
return params.materializedJobs.map((job, jobIndex)=>({
|
|
145
236
|
job: {
|
|
146
237
|
key: job.key,
|
|
147
238
|
mode: job.mode,
|
|
148
|
-
name:
|
|
239
|
+
name: job.name ?? null,
|
|
149
240
|
status: 'pending',
|
|
150
241
|
checkoutPersistCredentials: job.checkout.persistCredentials,
|
|
151
242
|
checkoutPermissionsContents: job.checkout.permissions.contents,
|
|
@@ -173,7 +264,7 @@ function materializeRunGraphJobs(params) {
|
|
|
173
264
|
},
|
|
174
265
|
createExecution: (jobRow)=>{
|
|
175
266
|
if (jobRow.mode === 'listening') return undefined;
|
|
176
|
-
const fallbackName =
|
|
267
|
+
const fallbackName = jobRow.name ?? jobRow.key;
|
|
177
268
|
const modelJob = params.params.model.jobs[jobIndex];
|
|
178
269
|
if (!modelJob) return undefined;
|
|
179
270
|
const executionPlan = deriveInitialJobExecutionPlan({
|
|
@@ -189,7 +280,9 @@ function materializeRunGraphJobs(params) {
|
|
|
189
280
|
});
|
|
190
281
|
return {
|
|
191
282
|
sequence: 1,
|
|
192
|
-
|
|
283
|
+
// Persist only the resolved override. The core entity supplies the
|
|
284
|
+
// static job name/key when this is null.
|
|
285
|
+
name: executionPlan.nameOverride,
|
|
193
286
|
runner: [
|
|
194
287
|
...executionPlan.runner
|
|
195
288
|
],
|
|
@@ -213,12 +306,29 @@ function materializeRunGraphJobs(params) {
|
|
|
213
306
|
}
|
|
214
307
|
function referencedVariables(model, jobs) {
|
|
215
308
|
const references = [];
|
|
309
|
+
for (const job of model.jobs){
|
|
310
|
+
collectPredicateVariableReferences(job.if, references);
|
|
311
|
+
collectPredicateVariableReferences(job.success, references);
|
|
312
|
+
for (const trigger of [
|
|
313
|
+
...job.listening?.on ?? [],
|
|
314
|
+
...job.listening?.until ?? []
|
|
315
|
+
]){
|
|
316
|
+
collectPredicateVariableReferences(trigger.filter, references);
|
|
317
|
+
}
|
|
318
|
+
for (const step of job.steps){
|
|
319
|
+
collectPredicateVariableReferences(step.if, references);
|
|
320
|
+
collectPredicateVariableReferences(step.gate?.success, references);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
collectFieldVariableReferences(model.runName, references, {
|
|
324
|
+
field: 'workflow.run_name'
|
|
325
|
+
});
|
|
216
326
|
if (jobs.length > 0) {
|
|
217
327
|
collectTemplateVariableReferences(model.templates?.env, references);
|
|
218
328
|
}
|
|
219
329
|
for (const job of jobs){
|
|
220
|
-
collectFieldVariableReferences(job.
|
|
221
|
-
field: 'job.
|
|
330
|
+
collectFieldVariableReferences(job.executionName, references, {
|
|
331
|
+
field: 'job.execution_name'
|
|
222
332
|
});
|
|
223
333
|
for (const template of job.runnerTemplates ?? []){
|
|
224
334
|
collectFieldVariableReferences(template, references, {
|
|
@@ -233,12 +343,15 @@ function referencedVariables(model, jobs) {
|
|
|
233
343
|
collectFieldVariableReferences(step.templates?.name, references, {
|
|
234
344
|
field: 'step.name'
|
|
235
345
|
});
|
|
346
|
+
collectFieldVariableReferences(step.templates?.workingDirectory, references, {
|
|
347
|
+
field: 'step.working_directory'
|
|
348
|
+
});
|
|
236
349
|
if (step.kind === 'run') {
|
|
237
350
|
collectFieldVariableReferences(step.templates?.command, references, {
|
|
238
351
|
field: 'run'
|
|
239
352
|
});
|
|
240
353
|
collectTemplateVariableReferences(step.templates?.env, references);
|
|
241
|
-
} else {
|
|
354
|
+
} else if (step.kind === 'agent') {
|
|
242
355
|
collectFieldVariableReferences(step.templates?.prompt, references, {
|
|
243
356
|
field: 'agent.prompt'
|
|
244
357
|
});
|
|
@@ -248,11 +361,29 @@ function referencedVariables(model, jobs) {
|
|
|
248
361
|
collectFieldVariableReferences(step.templates?.provider, references, {
|
|
249
362
|
field: 'agent.provider'
|
|
250
363
|
});
|
|
364
|
+
} else if (step.kind === 'checkout') {
|
|
365
|
+
for (const [key, field] of WORKFLOW_MODEL_CHECKOUT_TARGET_FIELDS){
|
|
366
|
+
collectFieldVariableReferences(step.checkout.templates?.[key], references, {
|
|
367
|
+
field
|
|
368
|
+
});
|
|
369
|
+
}
|
|
251
370
|
}
|
|
252
371
|
}
|
|
253
372
|
}
|
|
254
373
|
return references;
|
|
255
374
|
}
|
|
375
|
+
function collectPredicateVariableReferences(expression, references) {
|
|
376
|
+
if (expression === undefined) return;
|
|
377
|
+
const keyAccess = analyzeContextKeyAccess(expression);
|
|
378
|
+
for (const reference of keyAccess.references){
|
|
379
|
+
if (reference.root !== 'vars') continue;
|
|
380
|
+
references.push({
|
|
381
|
+
key: reference.key,
|
|
382
|
+
field: 'env',
|
|
383
|
+
source: typeof expression === 'string' ? expression : expression.source
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
256
387
|
function collectTemplateVariableReferences(templates, references, source) {
|
|
257
388
|
for (const [envKey, template] of Object.entries(templates ?? {})){
|
|
258
389
|
collectFieldVariableReferences(template, references, source === undefined ? {
|
|
@@ -276,10 +407,6 @@ function collectFieldVariableReferences(template, references, source) {
|
|
|
276
407
|
}
|
|
277
408
|
}
|
|
278
409
|
}
|
|
279
|
-
function workflowTemplateSource(template) {
|
|
280
|
-
if (template === undefined) return null;
|
|
281
|
-
return template.map((segment)=>segment.kind === 'literal' ? segment.value : `$${'{{'} ${segment.expression.source} ${'}}'}`).join('');
|
|
282
|
-
}
|
|
283
410
|
function logTemplateDiagnostics(params) {
|
|
284
411
|
if (params.diagnostics.length === 0) return;
|
|
285
412
|
logger().warn({
|