@shipfox/api-workflows 12.1.0 → 12.2.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 +4 -4
- package/CHANGELOG.md +29 -0
- package/dist/core/entities/job.d.ts +1 -1
- package/dist/core/entities/job.d.ts.map +1 -1
- package/dist/core/entities/step.d.ts +2 -2
- package/dist/core/entities/step.d.ts.map +1 -1
- package/dist/core/errors.d.ts +16 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +18 -0
- package/dist/core/errors.js.map +1 -1
- package/dist/core/step-config/assemble-run-context.d.ts +15 -5
- package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
- package/dist/core/step-config/assemble-run-context.js +77 -27
- package/dist/core/step-config/assemble-run-context.js.map +1 -1
- package/dist/core/step-config/fields.d.ts +5 -0
- package/dist/core/step-config/fields.d.ts.map +1 -1
- package/dist/core/step-config/fields.js +21 -3
- package/dist/core/step-config/fields.js.map +1 -1
- package/dist/core/step-config/index.d.ts +1 -1
- package/dist/core/step-config/index.d.ts.map +1 -1
- package/dist/core/step-config/index.js +1 -1
- package/dist/core/step-config/index.js.map +1 -1
- package/dist/core/step-config/job-output-limits.d.ts +11 -0
- package/dist/core/step-config/job-output-limits.d.ts.map +1 -0
- package/dist/core/step-config/job-output-limits.js +88 -0
- package/dist/core/step-config/job-output-limits.js.map +1 -0
- package/dist/core/step-config/materialize-workflow-model.d.ts +1 -1
- package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
- package/dist/core/step-config/materialize-workflow-model.js +41 -14
- package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
- package/dist/db/db.d.ts +50 -50
- package/dist/db/job-listeners.d.ts.map +1 -1
- package/dist/db/job-listeners.js +6 -5
- package/dist/db/job-listeners.js.map +1 -1
- package/dist/db/schema/job-executions.d.ts +3 -3
- package/dist/db/schema/job-listener-events.d.ts +1 -1
- package/dist/db/schema/jobs.d.ts +7 -7
- package/dist/db/schema/outbox.d.ts +1 -1
- package/dist/db/schema/step-attempts.d.ts +2 -2
- package/dist/db/schema/steps.d.ts +5 -5
- package/dist/db/schema/workflow-run-attempts.d.ts +3 -3
- package/dist/db/schema/workflow-run-counters.d.ts +1 -1
- package/dist/db/schema/workflow-runs.d.ts +2 -2
- package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
- package/dist/db/workflow-runs/job-executions.js +4 -2
- package/dist/db/workflow-runs/job-executions.js.map +1 -1
- package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
- package/dist/db/workflow-runs/jobs.js +29 -3
- package/dist/db/workflow-runs/jobs.js.map +1 -1
- package/dist/presentation/routes/project-access.d.ts +1 -1
- package/dist/temporal/activities/index.d.ts +1 -1
- package/dist/temporal/activities/index.d.ts.map +1 -1
- package/dist/temporal/activities/orchestration-activities.d.ts +1 -1
- package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
- package/dist/temporal/workflows/test-env.d.ts +2 -2
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/src/core/errors.ts +35 -0
- package/src/core/step-config/assemble-run-context.test.ts +232 -20
- package/src/core/step-config/assemble-run-context.ts +126 -28
- package/src/core/step-config/fields.ts +42 -3
- package/src/core/step-config/index.ts +2 -0
- package/src/core/step-config/job-output-limits.ts +130 -0
- package/src/core/step-config/materialize-workflow-model.test.ts +306 -1
- package/src/core/step-config/materialize-workflow-model.ts +60 -15
- package/src/db/job-listeners.ts +14 -3
- package/src/db/workflow-runs/job-executions.test.ts +207 -1
- package/src/db/workflow-runs/job-executions.ts +15 -2
- package/src/db/workflow-runs/jobs.test.ts +49 -0
- package/src/db/workflow-runs/jobs.ts +46 -6
- package/src/db/workflow-runs/run-create.test.ts +56 -0
- package/test/factories/workflow-model.ts +2 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/job-listeners.ts"],"sourcesContent":["import type {AgentInterModuleClient} from '@shipfox/api-agent-dto/inter-module';\nimport {readPersistedWorkflowModel} from '@shipfox/api-definitions-dto';\nimport type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {SecretsInterModuleClient} from '@shipfox/api-secrets-dto/inter-module';\nimport {\n WORKFLOWS_JOB_ACTIVATED,\n type WorkflowsJobActivatedEventDto,\n} from '@shipfox/api-workflows-dto';\nimport {and, asc, count, eq, inArray, isNull, notInArray, sql} from 'drizzle-orm';\nimport {type AgentDefaultsResolver, createAgentDefaultsResolver} from '#core/agent-defaults.js';\nimport {loadAgentToolMaterializationContext} from '#core/agent-tools.js';\nimport {isJobTerminal, type JobStatus, type ResolutionReason} from '#core/entities/job.js';\nimport type {\n JobExecution,\n JobExecutionStatus,\n WorkflowExecutionEvent,\n} from '#core/entities/job-execution.js';\nimport {normalizeWorkflowExecutionEvent} from '#core/entities/job-execution.js';\nimport {InterpolationUnresolvableError} from '#core/errors.js';\nimport {type DeriveJobSuccessResult, deriveJobSuccess} from '#core/job-transition/index.js';\nimport {\n type MaterializedListenerExecution,\n materializeListenerExecution,\n} from '#core/listener-execution-materialization.js';\nimport {\n applyListenerFilterSnapshots,\n assembleListenerSnapshotContext,\n type ListenerTriggerWithSnapshot,\n planListenerFilterSnapshots,\n} from '#core/step-config/assemble-run-context.js';\nimport {\n recordListenerEventsCoalesced,\n recordWorkflowJobExecutionStatusChanged,\n recordWorkflowListenerResolved,\n} from '#metrics/instance.js';\nimport {db, type Tx} from './db.js';\nimport {writeWorkflowsOutboxEvent} from './outbox-writes.js';\nimport {type JobExecutionDb, jobExecutions, toJobExecution} from './schema/job-executions.js';\nimport {type JobListenerEventDb, jobListenerEvents} from './schema/job-listener-events.js';\nimport {jobs, toJob} from './schema/jobs.js';\nimport {steps} from './schema/steps.js';\nimport {workflowRunAttempts} from './schema/workflow-run-attempts.js';\nimport {toWorkflowRun, workflowRuns} from './schema/workflow-runs.js';\nimport {\n bulkUpdateStepStatuses,\n getDirectDependencyJobContexts,\n loadReferencedVariables,\n updateJobStatusAtVersion,\n} from './workflow-runs.js';\n\nconst TERMINAL_EXECUTION_STATUSES: JobExecutionStatus[] = ['succeeded', 'failed', 'cancelled'];\nconst MAX_LISTENER_RESOLUTION_ATTEMPTS = 3;\n\nexport interface ActivateJobListenerParams {\n jobId: string;\n expectedVersion: number;\n}\n\nexport interface ActivateJobListenerResult {\n status: 'running' | 'terminal';\n jobStatus: JobStatus;\n jobVersion: number;\n executionCount: number;\n}\n\ntype JobActivatedListenerMatcher = Extract<\n WorkflowsJobActivatedEventDto,\n {mode: 'listening'}\n>['on'][number] &\n ListenerTriggerWithSnapshot;\n\nfunction applyActivatedListenerFilterSnapshots(\n plans: Parameters<typeof applyListenerFilterSnapshots>[0],\n context: Parameters<typeof applyListenerFilterSnapshots>[1],\n): JobActivatedListenerMatcher[] {\n return applyListenerFilterSnapshots(plans, context);\n}\n\nexport async function activateJobListener(\n params: ActivateJobListenerParams,\n): Promise<ActivateJobListenerResult> {\n return await db().transaction(async (tx) => {\n const [target] = await tx\n .select({job: jobs, attempt: workflowRunAttempts, run: workflowRuns})\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(jobs.id, params.jobId))\n .limit(1)\n .for('update');\n if (!target) throw new Error(`Job not found: ${params.jobId}`);\n\n const [{value: executionCount} = {value: 0}] = await tx\n .select({value: count()})\n .from(jobExecutions)\n .where(eq(jobExecutions.jobId, params.jobId));\n\n if (['succeeded', 'failed', 'cancelled', 'skipped'].includes(target.job.status)) {\n return {\n status: 'terminal',\n jobStatus: target.job.status,\n jobVersion: target.job.version,\n executionCount,\n };\n }\n\n let job = toJob(target.job);\n if (target.job.status === 'pending') {\n const updated = await updateJobStatusAtVersion(tx, {\n jobId: params.jobId,\n status: 'running',\n expectedVersion: params.expectedVersion,\n });\n if (!updated) {\n const [existing] = await tx.select().from(jobs).where(eq(jobs.id, params.jobId)).limit(1);\n if (existing?.status !== 'running') {\n throw new Error(\n `Optimistic lock failure activating listener job ${params.jobId} version ${params.expectedVersion}`,\n );\n }\n job = toJob(existing);\n } else {\n job = updated.job;\n }\n }\n\n const listenerRows = await tx\n .update(jobs)\n .set({listenerStatus: 'listening', updatedAt: new Date()})\n .where(and(eq(jobs.id, params.jobId), eq(jobs.listenerStatus, 'inactive')))\n .returning();\n\n if (listenerRows[0]) {\n const matchers = {\n on: target.job.listeningOn ?? [],\n until: target.job.listeningUntil ?? null,\n };\n const snapshotPlan = planListenerFilterSnapshots(matchers);\n const dependencyJobs =\n snapshotPlan.jobKeys.size === 0\n ? []\n : await getDirectDependencyJobContexts(params.jobId, tx);\n const snapshotContext = assembleListenerSnapshotContext({\n job: toJob(target.job),\n run: toWorkflowRun(target.run),\n triggerPayload: target.run.triggerPayload,\n inputs: target.run.inputs,\n vars: target.attempt.vars ?? undefined,\n plan: snapshotPlan,\n dependencyJobs,\n });\n\n await writeWorkflowsOutboxEvent(tx, {\n type: WORKFLOWS_JOB_ACTIVATED,\n payload: {\n jobId: params.jobId,\n workflowRunId: target.run.id,\n workspaceId: target.run.workspaceId,\n mode: 'listening',\n on: applyActivatedListenerFilterSnapshots(snapshotPlan.on, snapshotContext),\n until:\n matchers.until === null\n ? null\n : applyActivatedListenerFilterSnapshots(snapshotPlan.until, snapshotContext),\n },\n });\n }\n\n return {status: 'running', jobStatus: job.status, jobVersion: job.version, executionCount};\n });\n}\n\nexport type DrainListenerEventsResult =\n | {\n kind: 'execution';\n jobExecutionId: string;\n executionVersion: number;\n sequence: number;\n requiredLabels: string[];\n status: JobExecutionStatus;\n }\n | {kind: 'resolve-requested'}\n | {kind: 'empty'};\n\nexport interface DrainListenerEventsParams {\n jobId: string;\n expectedSequence: number;\n maxSize?: number | undefined;\n integrations?: IntegrationsModuleClient | undefined;\n projects?: ProjectsModuleClient | undefined;\n resolveAgentDefaults?: AgentDefaultsResolver | undefined;\n agent?: AgentInterModuleClient | undefined;\n secrets?: Pick<SecretsInterModuleClient, 'getVariablesByNamespace'> | undefined;\n}\n\nexport async function drainListenerEventsIntoExecution(\n params: DrainListenerEventsParams,\n): Promise<DrainListenerEventsResult> {\n const probeResult = await db().transaction(async (tx) => {\n const existing = await findExistingExecution(params, tx);\n if (existing) return existing;\n\n const resolveRequested = await hasPendingResolveEvent(params.jobId, tx);\n if (resolveRequested) return {kind: 'resolve-requested' as const};\n\n const hasBufferedFire = await hasBufferedFireEvent(params.jobId, tx);\n return hasBufferedFire ? null : {kind: 'empty' as const};\n });\n if (probeResult !== null) return probeResult;\n\n // Resolve external state before opening the persistence transaction. The\n // secrets module uses the shared pool and cannot reuse this transaction's\n // connection across the inter-module boundary.\n const materializationTarget = await loadListenerMaterializationTarget(params.jobId);\n const model =\n materializationTarget.attempt.model === null\n ? null\n : readPersistedWorkflowModel(materializationTarget.attempt.model);\n const modelJob = model?.jobs.find((job) => job.key === materializationTarget.job.key);\n let vars: Record<string, string> | undefined;\n let variableResolutionError: InterpolationUnresolvableError | undefined;\n if (model !== null && modelJob !== undefined) {\n try {\n vars = await loadReferencedVariables({\n model,\n jobs: [modelJob],\n workspaceId: materializationTarget.run.workspaceId,\n projectId: materializationTarget.run.projectId,\n definitionId: materializationTarget.run.definitionId,\n secrets: params.secrets,\n });\n } catch (error) {\n if (!(error instanceof InterpolationUnresolvableError)) throw error;\n variableResolutionError = error;\n }\n }\n const agentToolContext =\n materializationTarget.attempt.agentToolMaterialization === null\n ? await loadAgentToolMaterializationContext({\n model,\n workspaceId: materializationTarget.run.workspaceId,\n projectId: materializationTarget.run.projectId,\n integrations: params.integrations,\n projects: params.projects,\n })\n : undefined;\n\n const drained = await db().transaction(async (tx) => {\n const existing = await findExistingExecution(params, tx);\n if (existing) return {result: existing};\n\n const resolveRequested = await hasPendingResolveEvent(params.jobId, tx);\n if (resolveRequested) return {result: {kind: 'resolve-requested' as const}};\n\n const bufferedEvents = await lockBufferedFireEvents(params, tx);\n if (bufferedEvents.length === 0) return {result: {kind: 'empty' as const}};\n\n const target = await loadListenerMaterializationTarget(params.jobId, tx);\n const priorExecutions = await loadListenerPriorExecutions(\n params.jobId,\n target.job.name ?? target.job.key,\n tx,\n );\n const materialized = await materializeListenerExecution({\n model,\n run: toWorkflowRun(target.run),\n job: toJob(target.job),\n vars,\n variableResolutionError,\n sequence: params.expectedSequence,\n triggerEvents: listenerTriggerEvents(bufferedEvents),\n priorExecutions,\n resolveAgentDefaults:\n params.resolveAgentDefaults ??\n (params.agent\n ? createAgentDefaultsResolver(params.agent, target.run.workspaceId)\n : undefined),\n agentToolContext,\n agentToolSnapshot: target.attempt.agentToolMaterialization,\n });\n const execution = await persistMaterializedListenerExecution(tx, {\n jobId: params.jobId,\n sequence: params.expectedSequence,\n bufferedEventIds: bufferedEvents.map((event) => event.id),\n materialized,\n });\n\n if (materialized.status === 'failed') {\n recordWorkflowJobExecutionStatusChanged(materialized.status);\n }\n\n return {\n result: drainExecutionResult(execution),\n batchSize: bufferedEvents.length,\n };\n });\n\n if (drained.result.kind === 'execution' && drained.batchSize !== undefined) {\n recordListenerEventsCoalesced(drained.batchSize);\n }\n\n return drained.result;\n}\n\nexport interface ListenerBufferPeek {\n fireCount: number;\n resolvePending: boolean;\n oldestAgeMs: number;\n newestAgeMs: number;\n}\n\nexport async function peekListenerBuffer(params: {jobId: string}): Promise<ListenerBufferPeek> {\n const [row] = await db()\n .select({\n fireCount: sql<number>`count(*) filter (where ${jobListenerEvents.disposition} = 'fire')::integer`,\n resolvePending: sql<boolean>`coalesce(bool_or(${jobListenerEvents.disposition} = 'resolve'), false)`,\n oldestAgeMs: sql<number>`coalesce(floor(extract(epoch from (statement_timestamp() - min(${jobListenerEvents.receivedAt}) filter (where ${jobListenerEvents.disposition} = 'fire'))) * 1000), 0)::integer`,\n newestAgeMs: sql<number>`coalesce(floor(extract(epoch from (statement_timestamp() - max(${jobListenerEvents.receivedAt}) filter (where ${jobListenerEvents.disposition} = 'fire'))) * 1000), 0)::integer`,\n })\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, params.jobId),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n );\n\n return {\n fireCount: row?.fireCount ?? 0,\n resolvePending: row?.resolvePending ?? false,\n oldestAgeMs: row?.oldestAgeMs ?? 0,\n newestAgeMs: row?.newestAgeMs ?? 0,\n };\n}\n\nexport async function resolveJobListener(params: {\n jobId: string;\n reason: ResolutionReason;\n}): Promise<{status: 'succeeded' | 'failed'; jobVersion: number}> {\n let result: ApplyJobListenerResolutionResult | undefined;\n for (let attempt = 0; attempt < MAX_LISTENER_RESOLUTION_ATTEMPTS; attempt += 1) {\n const decision = await deriveJobListenerResolutionDecision(params.jobId);\n result = await applyJobListenerResolution(params, decision);\n if (result.kind === 'applied') break;\n }\n\n if (result?.kind !== 'applied') {\n throw new Error(`Optimistic lock failure resolving listener job ${params.jobId}`);\n }\n\n if (result.changed) recordWorkflowListenerResolved(params.reason);\n return {status: result.status, jobVersion: result.jobVersion};\n}\n\ntype JobListenerResolutionDecision = DeriveJobSuccessResult & {\n expectedVersion: number;\n};\n\ntype ApplyJobListenerResolutionResult =\n | {\n kind: 'applied';\n status: 'succeeded' | 'failed';\n jobVersion: number;\n changed: boolean;\n }\n | {kind: 'stale'};\n\nasync function deriveJobListenerResolutionDecision(\n jobId: string,\n): Promise<JobListenerResolutionDecision> {\n const [target] = await db()\n .select({job: jobs, attempt: workflowRunAttempts})\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .where(eq(jobs.id, jobId))\n .limit(1);\n const jobRow = target?.job;\n if (!jobRow) throw new Error(`Job not found: ${jobId}`);\n\n const [executionRows, dependencyJobs] = await Promise.all([\n db()\n .select()\n .from(jobExecutions)\n .where(eq(jobExecutions.jobId, jobId))\n .orderBy(asc(jobExecutions.sequence), asc(jobExecutions.id)),\n getDirectDependencyJobContexts(jobId),\n ]);\n return {\n expectedVersion: jobRow.version,\n ...deriveJobSuccess({\n success: jobRow.success,\n executions: executionRows.map((execution) =>\n toJobExecution(execution, jobRow.name ?? jobRow.key),\n ),\n jobs: dependencyJobs,\n vars: target.attempt.vars ?? undefined,\n }),\n };\n}\n\nasync function applyJobListenerResolution(\n params: {\n jobId: string;\n reason: ResolutionReason;\n },\n decision: JobListenerResolutionDecision,\n): Promise<ApplyJobListenerResolutionResult> {\n return await db().transaction(async (tx) => {\n const [jobRow] = await tx\n .select()\n .from(jobs)\n .where(eq(jobs.id, params.jobId))\n .limit(1)\n .for('update');\n if (!jobRow) throw new Error(`Job not found: ${params.jobId}`);\n\n if (jobRow.version !== decision.expectedVersion && !isJobTerminal(jobRow.status)) {\n return {kind: 'stale' as const};\n }\n\n const listenerRows = await tx\n .update(jobs)\n .set({\n listenerStatus: 'resolved',\n resolutionReason: params.reason,\n updatedAt: new Date(),\n })\n .where(and(eq(jobs.id, params.jobId), notInArray(jobs.listenerStatus, ['resolved'])))\n .returning({id: jobs.id});\n\n const updated = await updateJobStatusAtVersion(tx, {\n jobId: params.jobId,\n status: decision.status,\n expectedVersion: decision.expectedVersion,\n statusReason: decision.statusReason,\n evaluationTrace: decision.trace,\n });\n const job = updated?.job ?? toJob(jobRow);\n const resolvedStatus: 'succeeded' | 'failed' =\n job.status === 'succeeded' ? 'succeeded' : 'failed';\n return {\n kind: 'applied' as const,\n status: resolvedStatus,\n jobVersion: job.version,\n changed: listenerRows.length > 0 || updated?.changed === true,\n };\n });\n}\n\nexport async function settleListenerJobExecution(params: {\n jobExecutionId: string;\n status: Extract<JobExecutionStatus, 'failed' | 'cancelled'>;\n}): Promise<void> {\n const changed = await db().transaction(async (tx) => {\n const [execution] = await tx\n .update(jobExecutions)\n .set({\n status: params.status,\n statusReason: params.status === 'failed' ? 'step_failed' : 'run_cancelled',\n version: sql`${jobExecutions.version} + 1`,\n updatedAt: new Date(),\n finishedAt: sql`now()`,\n })\n .where(\n and(\n eq(jobExecutions.id, params.jobExecutionId),\n notInArray(jobExecutions.status, TERMINAL_EXECUTION_STATUSES),\n ),\n )\n .returning();\n if (!execution) return false;\n await bulkUpdateStepStatuses(\n {jobExecutionId: params.jobExecutionId, status: params.status},\n tx,\n );\n return true;\n });\n\n if (changed) {\n recordWorkflowJobExecutionStatusChanged(params.status);\n }\n}\n\nexport async function countActiveListeners(): Promise<number> {\n const [row] = await db()\n .select({value: count()})\n .from(jobs)\n .where(eq(jobs.listenerStatus, 'listening'));\n return row?.value ?? 0;\n}\n\nasync function findExistingExecution(\n params: DrainListenerEventsParams,\n tx: Tx,\n): Promise<Extract<DrainListenerEventsResult, {kind: 'execution'}> | undefined> {\n const [existing] = await tx\n .select()\n .from(jobExecutions)\n .where(\n and(\n eq(jobExecutions.jobId, params.jobId),\n eq(jobExecutions.sequence, params.expectedSequence),\n ),\n )\n .limit(1);\n if (!existing) return undefined;\n return drainExecutionResult(existing);\n}\n\nasync function hasPendingResolveEvent(jobId: string, tx: Tx): Promise<boolean> {\n const [resolveEvent] = await tx\n .select({id: jobListenerEvents.id})\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, jobId),\n eq(jobListenerEvents.disposition, 'resolve'),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n )\n .orderBy(asc(jobListenerEvents.receivedAt), asc(jobListenerEvents.id))\n .limit(1)\n .for('update');\n return resolveEvent !== undefined;\n}\n\nasync function hasBufferedFireEvent(jobId: string, tx: Tx): Promise<boolean> {\n const [fireEvent] = await tx\n .select({id: jobListenerEvents.id})\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, jobId),\n eq(jobListenerEvents.disposition, 'fire'),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n )\n .limit(1);\n return fireEvent !== undefined;\n}\n\nasync function lockBufferedFireEvents(\n params: DrainListenerEventsParams,\n tx: Tx,\n): Promise<JobListenerEventDb[]> {\n const bufferedQuery = tx\n .select()\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, params.jobId),\n eq(jobListenerEvents.disposition, 'fire'),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n )\n .orderBy(asc(jobListenerEvents.receivedAt), asc(jobListenerEvents.id));\n return await (params.maxSize === undefined\n ? bufferedQuery\n : bufferedQuery.limit(params.maxSize)\n ).for('update');\n}\n\nfunction listenerTriggerEvents(\n bufferedEvents: readonly JobListenerEventDb[],\n): WorkflowExecutionEvent[] {\n return bufferedEvents.map((event) =>\n normalizeWorkflowExecutionEvent({\n source: event.source,\n event: event.event,\n delivery_id: event.deliveryId,\n received_at: event.receivedAt.toISOString(),\n project: event.triggerReference?.project ?? null,\n repository: event.triggerReference?.repository ?? null,\n ref: event.triggerReference?.ref ?? null,\n commit: event.triggerReference?.commit ?? null,\n data: event.payload,\n }),\n );\n}\n\nasync function persistMaterializedListenerExecution(\n tx: Tx,\n params: {\n readonly jobId: string;\n readonly sequence: number;\n readonly bufferedEventIds: readonly string[];\n readonly materialized: MaterializedListenerExecution;\n },\n): Promise<JobExecutionDb> {\n const [execution] = await tx\n .insert(jobExecutions)\n .values({\n jobId: params.jobId,\n sequence: params.sequence,\n name: params.materialized.nameOverride,\n runner: params.materialized.runner.length === 0 ? null : [...params.materialized.runner],\n status: params.materialized.status,\n statusReason: params.materialized.statusReason,\n triggerEvents: [...params.materialized.triggerEvents],\n evaluationTrace: params.materialized.evaluationTrace,\n ...(params.materialized.status === 'failed' ? {finishedAt: sql`now()`} : {}),\n })\n .returning();\n if (!execution) throw new Error('Insert returned no rows');\n\n await tx\n .update(jobListenerEvents)\n .set({consumedByExecutionId: execution.id})\n .where(inArray(jobListenerEvents.id, [...params.bufferedEventIds]));\n\n if (params.materialized.status === 'pending' && params.materialized.steps.length > 0) {\n await tx.insert(steps).values(\n params.materialized.steps.map((step) => ({\n jobExecutionId: execution.id,\n key: step.key,\n name: step.name,\n sourceLocation: step.sourceLocation,\n status: step.status,\n type: step.type,\n config: step.config,\n configPlan: step.configPlan ?? null,\n authoredConfig: step.authoredConfig,\n condition: step.condition ?? null,\n position: step.position,\n })),\n );\n }\n\n return execution;\n}\n\nfunction drainExecutionResult(\n execution: JobExecutionDb,\n): Extract<DrainListenerEventsResult, {kind: 'execution'}> {\n return {\n kind: 'execution',\n jobExecutionId: execution.id,\n executionVersion: execution.version,\n sequence: execution.sequence,\n requiredLabels: execution.runner ?? [],\n status: execution.status,\n };\n}\n\nasync function loadListenerMaterializationTarget(jobId: string, tx?: Tx) {\n const query = (tx ?? db())\n .select({job: jobs, attempt: workflowRunAttempts, run: workflowRuns})\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(jobs.id, jobId))\n .limit(1);\n const [target] = tx === undefined ? await query : await query.for('update');\n if (!target) throw new Error(`Job not found: ${jobId}`);\n\n return target;\n}\n\nasync function loadListenerPriorExecutions(\n jobId: string,\n fallbackName: string,\n tx: Tx,\n): Promise<JobExecution[]> {\n const priorExecutions = await tx\n .select()\n .from(jobExecutions)\n .where(eq(jobExecutions.jobId, jobId))\n .orderBy(asc(jobExecutions.sequence), asc(jobExecutions.id));\n return priorExecutions.map((execution) => toJobExecution(execution, fallbackName));\n}\n"],"names":["readPersistedWorkflowModel","WORKFLOWS_JOB_ACTIVATED","and","asc","count","eq","inArray","isNull","notInArray","sql","createAgentDefaultsResolver","loadAgentToolMaterializationContext","isJobTerminal","normalizeWorkflowExecutionEvent","InterpolationUnresolvableError","deriveJobSuccess","materializeListenerExecution","applyListenerFilterSnapshots","assembleListenerSnapshotContext","planListenerFilterSnapshots","recordListenerEventsCoalesced","recordWorkflowJobExecutionStatusChanged","recordWorkflowListenerResolved","db","writeWorkflowsOutboxEvent","jobExecutions","toJobExecution","jobListenerEvents","jobs","toJob","steps","workflowRunAttempts","toWorkflowRun","workflowRuns","bulkUpdateStepStatuses","getDirectDependencyJobContexts","loadReferencedVariables","updateJobStatusAtVersion","TERMINAL_EXECUTION_STATUSES","MAX_LISTENER_RESOLUTION_ATTEMPTS","applyActivatedListenerFilterSnapshots","plans","context","activateJobListener","params","transaction","tx","target","select","job","attempt","run","from","innerJoin","workflowRunAttemptId","id","workflowRunId","where","jobId","limit","for","Error","value","executionCount","includes","status","jobStatus","jobVersion","version","updated","expectedVersion","existing","listenerRows","update","set","listenerStatus","updatedAt","Date","returning","matchers","on","listeningOn","until","listeningUntil","snapshotPlan","dependencyJobs","jobKeys","size","snapshotContext","triggerPayload","inputs","vars","undefined","plan","type","payload","workspaceId","mode","drainListenerEventsIntoExecution","probeResult","findExistingExecution","resolveRequested","hasPendingResolveEvent","kind","hasBufferedFire","hasBufferedFireEvent","materializationTarget","loadListenerMaterializationTarget","model","modelJob","find","key","variableResolutionError","projectId","definitionId","secrets","error","agentToolContext","agentToolMaterialization","integrations","projects","drained","result","bufferedEvents","lockBufferedFireEvents","length","priorExecutions","loadListenerPriorExecutions","name","materialized","sequence","expectedSequence","triggerEvents","listenerTriggerEvents","resolveAgentDefaults","agent","agentToolSnapshot","execution","persistMaterializedListenerExecution","bufferedEventIds","map","event","drainExecutionResult","batchSize","peekListenerBuffer","row","fireCount","disposition","resolvePending","oldestAgeMs","receivedAt","newestAgeMs","consumedByExecutionId","resolveJobListener","decision","deriveJobListenerResolutionDecision","applyJobListenerResolution","changed","reason","jobRow","executionRows","Promise","all","orderBy","success","executions","resolutionReason","statusReason","evaluationTrace","trace","resolvedStatus","settleListenerJobExecution","finishedAt","jobExecutionId","countActiveListeners","resolveEvent","fireEvent","bufferedQuery","maxSize","source","delivery_id","deliveryId","received_at","toISOString","project","triggerReference","repository","ref","commit","data","insert","values","nameOverride","runner","step","sourceLocation","config","configPlan","authoredConfig","condition","position","executionVersion","requiredLabels","query","fallbackName"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/job-listeners.ts"],"sourcesContent":["import type {AgentInterModuleClient} from '@shipfox/api-agent-dto/inter-module';\nimport {readPersistedWorkflowModel} from '@shipfox/api-definitions-dto';\nimport type {IntegrationsModuleClient} from '@shipfox/api-integration-core-dto/inter-module';\nimport type {ProjectsModuleClient} from '@shipfox/api-projects-dto/inter-module';\nimport type {SecretsInterModuleClient} from '@shipfox/api-secrets-dto/inter-module';\nimport {\n WORKFLOWS_JOB_ACTIVATED,\n type WorkflowsJobActivatedEventDto,\n} from '@shipfox/api-workflows-dto';\nimport {and, asc, count, eq, inArray, isNull, notInArray, sql} from 'drizzle-orm';\nimport {type AgentDefaultsResolver, createAgentDefaultsResolver} from '#core/agent-defaults.js';\nimport {loadAgentToolMaterializationContext} from '#core/agent-tools.js';\nimport {isJobTerminal, type JobStatus, type ResolutionReason} from '#core/entities/job.js';\nimport type {\n JobExecution,\n JobExecutionStatus,\n WorkflowExecutionEvent,\n} from '#core/entities/job-execution.js';\nimport {normalizeWorkflowExecutionEvent} from '#core/entities/job-execution.js';\nimport {InterpolationUnresolvableError} from '#core/errors.js';\nimport {type DeriveJobSuccessResult, deriveJobSuccess} from '#core/job-transition/index.js';\nimport {\n type MaterializedListenerExecution,\n materializeListenerExecution,\n} from '#core/listener-execution-materialization.js';\nimport {\n applyListenerFilterSnapshots,\n assembleListenerSnapshotContext,\n type ListenerTriggerWithSnapshot,\n listenerFilterOutputTypesForJobs,\n planListenerFilterSnapshots,\n} from '#core/step-config/assemble-run-context.js';\nimport {\n recordListenerEventsCoalesced,\n recordWorkflowJobExecutionStatusChanged,\n recordWorkflowListenerResolved,\n} from '#metrics/instance.js';\nimport {db, type Tx} from './db.js';\nimport {writeWorkflowsOutboxEvent} from './outbox-writes.js';\nimport {type JobExecutionDb, jobExecutions, toJobExecution} from './schema/job-executions.js';\nimport {type JobListenerEventDb, jobListenerEvents} from './schema/job-listener-events.js';\nimport {jobs, toJob} from './schema/jobs.js';\nimport {steps} from './schema/steps.js';\nimport {workflowRunAttempts} from './schema/workflow-run-attempts.js';\nimport {toWorkflowRun, workflowRuns} from './schema/workflow-runs.js';\nimport {\n bulkUpdateStepStatuses,\n getDirectDependencyJobContexts,\n loadReferencedVariables,\n updateJobStatusAtVersion,\n} from './workflow-runs.js';\n\nconst TERMINAL_EXECUTION_STATUSES: JobExecutionStatus[] = ['succeeded', 'failed', 'cancelled'];\nconst MAX_LISTENER_RESOLUTION_ATTEMPTS = 3;\n\nexport interface ActivateJobListenerParams {\n jobId: string;\n expectedVersion: number;\n}\n\nexport interface ActivateJobListenerResult {\n status: 'running' | 'terminal';\n jobStatus: JobStatus;\n jobVersion: number;\n executionCount: number;\n}\n\ntype JobActivatedListenerMatcher = Extract<\n WorkflowsJobActivatedEventDto,\n {mode: 'listening'}\n>['on'][number] &\n ListenerTriggerWithSnapshot;\n\nfunction applyActivatedListenerFilterSnapshots(\n plans: Parameters<typeof applyListenerFilterSnapshots>[0],\n context: Parameters<typeof applyListenerFilterSnapshots>[1],\n outputTypes: Parameters<typeof applyListenerFilterSnapshots>[2],\n): JobActivatedListenerMatcher[] {\n return applyListenerFilterSnapshots(plans, context, outputTypes);\n}\n\nexport async function activateJobListener(\n params: ActivateJobListenerParams,\n): Promise<ActivateJobListenerResult> {\n return await db().transaction(async (tx) => {\n const [target] = await tx\n .select({job: jobs, attempt: workflowRunAttempts, run: workflowRuns})\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(jobs.id, params.jobId))\n .limit(1)\n .for('update');\n if (!target) throw new Error(`Job not found: ${params.jobId}`);\n\n const [{value: executionCount} = {value: 0}] = await tx\n .select({value: count()})\n .from(jobExecutions)\n .where(eq(jobExecutions.jobId, params.jobId));\n\n if (['succeeded', 'failed', 'cancelled', 'skipped'].includes(target.job.status)) {\n return {\n status: 'terminal',\n jobStatus: target.job.status,\n jobVersion: target.job.version,\n executionCount,\n };\n }\n\n let job = toJob(target.job);\n if (target.job.status === 'pending') {\n const updated = await updateJobStatusAtVersion(tx, {\n jobId: params.jobId,\n status: 'running',\n expectedVersion: params.expectedVersion,\n });\n if (!updated) {\n const [existing] = await tx.select().from(jobs).where(eq(jobs.id, params.jobId)).limit(1);\n if (existing?.status !== 'running') {\n throw new Error(\n `Optimistic lock failure activating listener job ${params.jobId} version ${params.expectedVersion}`,\n );\n }\n job = toJob(existing);\n } else {\n job = updated.job;\n }\n }\n\n const listenerRows = await tx\n .update(jobs)\n .set({listenerStatus: 'listening', updatedAt: new Date()})\n .where(and(eq(jobs.id, params.jobId), eq(jobs.listenerStatus, 'inactive')))\n .returning();\n\n if (listenerRows[0]) {\n const matchers = {\n on: target.job.listeningOn ?? [],\n until: target.job.listeningUntil ?? null,\n };\n const snapshotPlan = planListenerFilterSnapshots(matchers);\n const dependencyJobs =\n snapshotPlan.jobKeys.size === 0\n ? []\n : await getDirectDependencyJobContexts(params.jobId, tx);\n const snapshotContext = assembleListenerSnapshotContext({\n job: toJob(target.job),\n run: toWorkflowRun(target.run),\n triggerPayload: target.run.triggerPayload,\n inputs: target.run.inputs,\n vars: target.attempt.vars ?? undefined,\n plan: snapshotPlan,\n dependencyJobs,\n });\n const listenerOutputTypes = listenerFilterOutputTypesForJobs(dependencyJobs);\n\n await writeWorkflowsOutboxEvent(tx, {\n type: WORKFLOWS_JOB_ACTIVATED,\n payload: {\n jobId: params.jobId,\n workflowRunId: target.run.id,\n workspaceId: target.run.workspaceId,\n mode: 'listening',\n on: applyActivatedListenerFilterSnapshots(\n snapshotPlan.on,\n snapshotContext,\n listenerOutputTypes,\n ),\n until:\n matchers.until === null\n ? null\n : applyActivatedListenerFilterSnapshots(\n snapshotPlan.until,\n snapshotContext,\n listenerOutputTypes,\n ),\n },\n });\n }\n\n return {status: 'running', jobStatus: job.status, jobVersion: job.version, executionCount};\n });\n}\n\nexport type DrainListenerEventsResult =\n | {\n kind: 'execution';\n jobExecutionId: string;\n executionVersion: number;\n sequence: number;\n requiredLabels: string[];\n status: JobExecutionStatus;\n }\n | {kind: 'resolve-requested'}\n | {kind: 'empty'};\n\nexport interface DrainListenerEventsParams {\n jobId: string;\n expectedSequence: number;\n maxSize?: number | undefined;\n integrations?: IntegrationsModuleClient | undefined;\n projects?: ProjectsModuleClient | undefined;\n resolveAgentDefaults?: AgentDefaultsResolver | undefined;\n agent?: AgentInterModuleClient | undefined;\n secrets?: Pick<SecretsInterModuleClient, 'getVariablesByNamespace'> | undefined;\n}\n\nexport async function drainListenerEventsIntoExecution(\n params: DrainListenerEventsParams,\n): Promise<DrainListenerEventsResult> {\n const probeResult = await db().transaction(async (tx) => {\n const existing = await findExistingExecution(params, tx);\n if (existing) return existing;\n\n const resolveRequested = await hasPendingResolveEvent(params.jobId, tx);\n if (resolveRequested) return {kind: 'resolve-requested' as const};\n\n const hasBufferedFire = await hasBufferedFireEvent(params.jobId, tx);\n return hasBufferedFire ? null : {kind: 'empty' as const};\n });\n if (probeResult !== null) return probeResult;\n\n // Resolve external state before opening the persistence transaction. The\n // secrets module uses the shared pool and cannot reuse this transaction's\n // connection across the inter-module boundary.\n const materializationTarget = await loadListenerMaterializationTarget(params.jobId);\n const model =\n materializationTarget.attempt.model === null\n ? null\n : readPersistedWorkflowModel(materializationTarget.attempt.model);\n const modelJob = model?.jobs.find((job) => job.key === materializationTarget.job.key);\n let vars: Record<string, string> | undefined;\n let variableResolutionError: InterpolationUnresolvableError | undefined;\n if (model !== null && modelJob !== undefined) {\n try {\n vars = await loadReferencedVariables({\n model,\n jobs: [modelJob],\n workspaceId: materializationTarget.run.workspaceId,\n projectId: materializationTarget.run.projectId,\n definitionId: materializationTarget.run.definitionId,\n secrets: params.secrets,\n });\n } catch (error) {\n if (!(error instanceof InterpolationUnresolvableError)) throw error;\n variableResolutionError = error;\n }\n }\n const agentToolContext =\n materializationTarget.attempt.agentToolMaterialization === null\n ? await loadAgentToolMaterializationContext({\n model,\n workspaceId: materializationTarget.run.workspaceId,\n projectId: materializationTarget.run.projectId,\n integrations: params.integrations,\n projects: params.projects,\n })\n : undefined;\n\n const drained = await db().transaction(async (tx) => {\n const existing = await findExistingExecution(params, tx);\n if (existing) return {result: existing};\n\n const resolveRequested = await hasPendingResolveEvent(params.jobId, tx);\n if (resolveRequested) return {result: {kind: 'resolve-requested' as const}};\n\n const bufferedEvents = await lockBufferedFireEvents(params, tx);\n if (bufferedEvents.length === 0) return {result: {kind: 'empty' as const}};\n\n const target = await loadListenerMaterializationTarget(params.jobId, tx);\n const priorExecutions = await loadListenerPriorExecutions(\n params.jobId,\n target.job.name ?? target.job.key,\n tx,\n );\n const materialized = await materializeListenerExecution({\n model,\n run: toWorkflowRun(target.run),\n job: toJob(target.job),\n vars,\n variableResolutionError,\n sequence: params.expectedSequence,\n triggerEvents: listenerTriggerEvents(bufferedEvents),\n priorExecutions,\n resolveAgentDefaults:\n params.resolveAgentDefaults ??\n (params.agent\n ? createAgentDefaultsResolver(params.agent, target.run.workspaceId)\n : undefined),\n agentToolContext,\n agentToolSnapshot: target.attempt.agentToolMaterialization,\n });\n const execution = await persistMaterializedListenerExecution(tx, {\n jobId: params.jobId,\n sequence: params.expectedSequence,\n bufferedEventIds: bufferedEvents.map((event) => event.id),\n materialized,\n });\n\n if (materialized.status === 'failed') {\n recordWorkflowJobExecutionStatusChanged(materialized.status);\n }\n\n return {\n result: drainExecutionResult(execution),\n batchSize: bufferedEvents.length,\n };\n });\n\n if (drained.result.kind === 'execution' && drained.batchSize !== undefined) {\n recordListenerEventsCoalesced(drained.batchSize);\n }\n\n return drained.result;\n}\n\nexport interface ListenerBufferPeek {\n fireCount: number;\n resolvePending: boolean;\n oldestAgeMs: number;\n newestAgeMs: number;\n}\n\nexport async function peekListenerBuffer(params: {jobId: string}): Promise<ListenerBufferPeek> {\n const [row] = await db()\n .select({\n fireCount: sql<number>`count(*) filter (where ${jobListenerEvents.disposition} = 'fire')::integer`,\n resolvePending: sql<boolean>`coalesce(bool_or(${jobListenerEvents.disposition} = 'resolve'), false)`,\n oldestAgeMs: sql<number>`coalesce(floor(extract(epoch from (statement_timestamp() - min(${jobListenerEvents.receivedAt}) filter (where ${jobListenerEvents.disposition} = 'fire'))) * 1000), 0)::integer`,\n newestAgeMs: sql<number>`coalesce(floor(extract(epoch from (statement_timestamp() - max(${jobListenerEvents.receivedAt}) filter (where ${jobListenerEvents.disposition} = 'fire'))) * 1000), 0)::integer`,\n })\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, params.jobId),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n );\n\n return {\n fireCount: row?.fireCount ?? 0,\n resolvePending: row?.resolvePending ?? false,\n oldestAgeMs: row?.oldestAgeMs ?? 0,\n newestAgeMs: row?.newestAgeMs ?? 0,\n };\n}\n\nexport async function resolveJobListener(params: {\n jobId: string;\n reason: ResolutionReason;\n}): Promise<{status: 'succeeded' | 'failed'; jobVersion: number}> {\n let result: ApplyJobListenerResolutionResult | undefined;\n for (let attempt = 0; attempt < MAX_LISTENER_RESOLUTION_ATTEMPTS; attempt += 1) {\n const decision = await deriveJobListenerResolutionDecision(params.jobId);\n result = await applyJobListenerResolution(params, decision);\n if (result.kind === 'applied') break;\n }\n\n if (result?.kind !== 'applied') {\n throw new Error(`Optimistic lock failure resolving listener job ${params.jobId}`);\n }\n\n if (result.changed) recordWorkflowListenerResolved(params.reason);\n return {status: result.status, jobVersion: result.jobVersion};\n}\n\ntype JobListenerResolutionDecision = DeriveJobSuccessResult & {\n expectedVersion: number;\n};\n\ntype ApplyJobListenerResolutionResult =\n | {\n kind: 'applied';\n status: 'succeeded' | 'failed';\n jobVersion: number;\n changed: boolean;\n }\n | {kind: 'stale'};\n\nasync function deriveJobListenerResolutionDecision(\n jobId: string,\n): Promise<JobListenerResolutionDecision> {\n const [target] = await db()\n .select({job: jobs, attempt: workflowRunAttempts})\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .where(eq(jobs.id, jobId))\n .limit(1);\n const jobRow = target?.job;\n if (!jobRow) throw new Error(`Job not found: ${jobId}`);\n\n const [executionRows, dependencyJobs] = await Promise.all([\n db()\n .select()\n .from(jobExecutions)\n .where(eq(jobExecutions.jobId, jobId))\n .orderBy(asc(jobExecutions.sequence), asc(jobExecutions.id)),\n getDirectDependencyJobContexts(jobId),\n ]);\n return {\n expectedVersion: jobRow.version,\n ...deriveJobSuccess({\n success: jobRow.success,\n executions: executionRows.map((execution) =>\n toJobExecution(execution, jobRow.name ?? jobRow.key),\n ),\n jobs: dependencyJobs,\n vars: target.attempt.vars ?? undefined,\n }),\n };\n}\n\nasync function applyJobListenerResolution(\n params: {\n jobId: string;\n reason: ResolutionReason;\n },\n decision: JobListenerResolutionDecision,\n): Promise<ApplyJobListenerResolutionResult> {\n return await db().transaction(async (tx) => {\n const [jobRow] = await tx\n .select()\n .from(jobs)\n .where(eq(jobs.id, params.jobId))\n .limit(1)\n .for('update');\n if (!jobRow) throw new Error(`Job not found: ${params.jobId}`);\n\n if (jobRow.version !== decision.expectedVersion && !isJobTerminal(jobRow.status)) {\n return {kind: 'stale' as const};\n }\n\n const listenerRows = await tx\n .update(jobs)\n .set({\n listenerStatus: 'resolved',\n resolutionReason: params.reason,\n updatedAt: new Date(),\n })\n .where(and(eq(jobs.id, params.jobId), notInArray(jobs.listenerStatus, ['resolved'])))\n .returning({id: jobs.id});\n\n const updated = await updateJobStatusAtVersion(tx, {\n jobId: params.jobId,\n status: decision.status,\n expectedVersion: decision.expectedVersion,\n statusReason: decision.statusReason,\n evaluationTrace: decision.trace,\n });\n const job = updated?.job ?? toJob(jobRow);\n const resolvedStatus: 'succeeded' | 'failed' =\n job.status === 'succeeded' ? 'succeeded' : 'failed';\n return {\n kind: 'applied' as const,\n status: resolvedStatus,\n jobVersion: job.version,\n changed: listenerRows.length > 0 || updated?.changed === true,\n };\n });\n}\n\nexport async function settleListenerJobExecution(params: {\n jobExecutionId: string;\n status: Extract<JobExecutionStatus, 'failed' | 'cancelled'>;\n}): Promise<void> {\n const changed = await db().transaction(async (tx) => {\n const [execution] = await tx\n .update(jobExecutions)\n .set({\n status: params.status,\n statusReason: params.status === 'failed' ? 'step_failed' : 'run_cancelled',\n version: sql`${jobExecutions.version} + 1`,\n updatedAt: new Date(),\n finishedAt: sql`now()`,\n })\n .where(\n and(\n eq(jobExecutions.id, params.jobExecutionId),\n notInArray(jobExecutions.status, TERMINAL_EXECUTION_STATUSES),\n ),\n )\n .returning();\n if (!execution) return false;\n await bulkUpdateStepStatuses(\n {jobExecutionId: params.jobExecutionId, status: params.status},\n tx,\n );\n return true;\n });\n\n if (changed) {\n recordWorkflowJobExecutionStatusChanged(params.status);\n }\n}\n\nexport async function countActiveListeners(): Promise<number> {\n const [row] = await db()\n .select({value: count()})\n .from(jobs)\n .where(eq(jobs.listenerStatus, 'listening'));\n return row?.value ?? 0;\n}\n\nasync function findExistingExecution(\n params: DrainListenerEventsParams,\n tx: Tx,\n): Promise<Extract<DrainListenerEventsResult, {kind: 'execution'}> | undefined> {\n const [existing] = await tx\n .select()\n .from(jobExecutions)\n .where(\n and(\n eq(jobExecutions.jobId, params.jobId),\n eq(jobExecutions.sequence, params.expectedSequence),\n ),\n )\n .limit(1);\n if (!existing) return undefined;\n return drainExecutionResult(existing);\n}\n\nasync function hasPendingResolveEvent(jobId: string, tx: Tx): Promise<boolean> {\n const [resolveEvent] = await tx\n .select({id: jobListenerEvents.id})\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, jobId),\n eq(jobListenerEvents.disposition, 'resolve'),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n )\n .orderBy(asc(jobListenerEvents.receivedAt), asc(jobListenerEvents.id))\n .limit(1)\n .for('update');\n return resolveEvent !== undefined;\n}\n\nasync function hasBufferedFireEvent(jobId: string, tx: Tx): Promise<boolean> {\n const [fireEvent] = await tx\n .select({id: jobListenerEvents.id})\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, jobId),\n eq(jobListenerEvents.disposition, 'fire'),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n )\n .limit(1);\n return fireEvent !== undefined;\n}\n\nasync function lockBufferedFireEvents(\n params: DrainListenerEventsParams,\n tx: Tx,\n): Promise<JobListenerEventDb[]> {\n const bufferedQuery = tx\n .select()\n .from(jobListenerEvents)\n .where(\n and(\n eq(jobListenerEvents.jobId, params.jobId),\n eq(jobListenerEvents.disposition, 'fire'),\n isNull(jobListenerEvents.consumedByExecutionId),\n ),\n )\n .orderBy(asc(jobListenerEvents.receivedAt), asc(jobListenerEvents.id));\n return await (params.maxSize === undefined\n ? bufferedQuery\n : bufferedQuery.limit(params.maxSize)\n ).for('update');\n}\n\nfunction listenerTriggerEvents(\n bufferedEvents: readonly JobListenerEventDb[],\n): WorkflowExecutionEvent[] {\n return bufferedEvents.map((event) =>\n normalizeWorkflowExecutionEvent({\n source: event.source,\n event: event.event,\n delivery_id: event.deliveryId,\n received_at: event.receivedAt.toISOString(),\n project: event.triggerReference?.project ?? null,\n repository: event.triggerReference?.repository ?? null,\n ref: event.triggerReference?.ref ?? null,\n commit: event.triggerReference?.commit ?? null,\n data: event.payload,\n }),\n );\n}\n\nasync function persistMaterializedListenerExecution(\n tx: Tx,\n params: {\n readonly jobId: string;\n readonly sequence: number;\n readonly bufferedEventIds: readonly string[];\n readonly materialized: MaterializedListenerExecution;\n },\n): Promise<JobExecutionDb> {\n const [execution] = await tx\n .insert(jobExecutions)\n .values({\n jobId: params.jobId,\n sequence: params.sequence,\n name: params.materialized.nameOverride,\n runner: params.materialized.runner.length === 0 ? null : [...params.materialized.runner],\n status: params.materialized.status,\n statusReason: params.materialized.statusReason,\n triggerEvents: [...params.materialized.triggerEvents],\n evaluationTrace: params.materialized.evaluationTrace,\n ...(params.materialized.status === 'failed' ? {finishedAt: sql`now()`} : {}),\n })\n .returning();\n if (!execution) throw new Error('Insert returned no rows');\n\n await tx\n .update(jobListenerEvents)\n .set({consumedByExecutionId: execution.id})\n .where(inArray(jobListenerEvents.id, [...params.bufferedEventIds]));\n\n if (params.materialized.status === 'pending' && params.materialized.steps.length > 0) {\n await tx.insert(steps).values(\n params.materialized.steps.map((step) => ({\n jobExecutionId: execution.id,\n key: step.key,\n name: step.name,\n sourceLocation: step.sourceLocation,\n status: step.status,\n type: step.type,\n config: step.config,\n configPlan: step.configPlan ?? null,\n authoredConfig: step.authoredConfig,\n condition: step.condition ?? null,\n position: step.position,\n })),\n );\n }\n\n return execution;\n}\n\nfunction drainExecutionResult(\n execution: JobExecutionDb,\n): Extract<DrainListenerEventsResult, {kind: 'execution'}> {\n return {\n kind: 'execution',\n jobExecutionId: execution.id,\n executionVersion: execution.version,\n sequence: execution.sequence,\n requiredLabels: execution.runner ?? [],\n status: execution.status,\n };\n}\n\nasync function loadListenerMaterializationTarget(jobId: string, tx?: Tx) {\n const query = (tx ?? db())\n .select({job: jobs, attempt: workflowRunAttempts, run: workflowRuns})\n .from(jobs)\n .innerJoin(workflowRunAttempts, eq(jobs.workflowRunAttemptId, workflowRunAttempts.id))\n .innerJoin(workflowRuns, eq(workflowRunAttempts.workflowRunId, workflowRuns.id))\n .where(eq(jobs.id, jobId))\n .limit(1);\n const [target] = tx === undefined ? await query : await query.for('update');\n if (!target) throw new Error(`Job not found: ${jobId}`);\n\n return target;\n}\n\nasync function loadListenerPriorExecutions(\n jobId: string,\n fallbackName: string,\n tx: Tx,\n): Promise<JobExecution[]> {\n const priorExecutions = await tx\n .select()\n .from(jobExecutions)\n .where(eq(jobExecutions.jobId, jobId))\n .orderBy(asc(jobExecutions.sequence), asc(jobExecutions.id));\n return priorExecutions.map((execution) => toJobExecution(execution, fallbackName));\n}\n"],"names":["readPersistedWorkflowModel","WORKFLOWS_JOB_ACTIVATED","and","asc","count","eq","inArray","isNull","notInArray","sql","createAgentDefaultsResolver","loadAgentToolMaterializationContext","isJobTerminal","normalizeWorkflowExecutionEvent","InterpolationUnresolvableError","deriveJobSuccess","materializeListenerExecution","applyListenerFilterSnapshots","assembleListenerSnapshotContext","listenerFilterOutputTypesForJobs","planListenerFilterSnapshots","recordListenerEventsCoalesced","recordWorkflowJobExecutionStatusChanged","recordWorkflowListenerResolved","db","writeWorkflowsOutboxEvent","jobExecutions","toJobExecution","jobListenerEvents","jobs","toJob","steps","workflowRunAttempts","toWorkflowRun","workflowRuns","bulkUpdateStepStatuses","getDirectDependencyJobContexts","loadReferencedVariables","updateJobStatusAtVersion","TERMINAL_EXECUTION_STATUSES","MAX_LISTENER_RESOLUTION_ATTEMPTS","applyActivatedListenerFilterSnapshots","plans","context","outputTypes","activateJobListener","params","transaction","tx","target","select","job","attempt","run","from","innerJoin","workflowRunAttemptId","id","workflowRunId","where","jobId","limit","for","Error","value","executionCount","includes","status","jobStatus","jobVersion","version","updated","expectedVersion","existing","listenerRows","update","set","listenerStatus","updatedAt","Date","returning","matchers","on","listeningOn","until","listeningUntil","snapshotPlan","dependencyJobs","jobKeys","size","snapshotContext","triggerPayload","inputs","vars","undefined","plan","listenerOutputTypes","type","payload","workspaceId","mode","drainListenerEventsIntoExecution","probeResult","findExistingExecution","resolveRequested","hasPendingResolveEvent","kind","hasBufferedFire","hasBufferedFireEvent","materializationTarget","loadListenerMaterializationTarget","model","modelJob","find","key","variableResolutionError","projectId","definitionId","secrets","error","agentToolContext","agentToolMaterialization","integrations","projects","drained","result","bufferedEvents","lockBufferedFireEvents","length","priorExecutions","loadListenerPriorExecutions","name","materialized","sequence","expectedSequence","triggerEvents","listenerTriggerEvents","resolveAgentDefaults","agent","agentToolSnapshot","execution","persistMaterializedListenerExecution","bufferedEventIds","map","event","drainExecutionResult","batchSize","peekListenerBuffer","row","fireCount","disposition","resolvePending","oldestAgeMs","receivedAt","newestAgeMs","consumedByExecutionId","resolveJobListener","decision","deriveJobListenerResolutionDecision","applyJobListenerResolution","changed","reason","jobRow","executionRows","Promise","all","orderBy","success","executions","resolutionReason","statusReason","evaluationTrace","trace","resolvedStatus","settleListenerJobExecution","finishedAt","jobExecutionId","countActiveListeners","resolveEvent","fireEvent","bufferedQuery","maxSize","source","delivery_id","deliveryId","received_at","toISOString","project","triggerReference","repository","ref","commit","data","insert","values","nameOverride","runner","step","sourceLocation","config","configPlan","authoredConfig","condition","position","executionVersion","requiredLabels","query","fallbackName"],"mappings":"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"}
|
|
@@ -97,7 +97,7 @@ export declare const jobExecutions: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
97
97
|
tableName: "job_executions";
|
|
98
98
|
dataType: "string";
|
|
99
99
|
columnType: "PgEnumColumn";
|
|
100
|
-
data: "
|
|
100
|
+
data: "cancelled" | "failed" | "pending" | "running" | "succeeded";
|
|
101
101
|
driverParam: string;
|
|
102
102
|
notNull: true;
|
|
103
103
|
hasDefault: true;
|
|
@@ -114,7 +114,7 @@ export declare const jobExecutions: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
114
114
|
tableName: "job_executions";
|
|
115
115
|
dataType: "string";
|
|
116
116
|
columnType: "PgEnumColumn";
|
|
117
|
-
data: "
|
|
117
|
+
data: "condition_errored" | "condition_false" | "condition_rejected" | "default_gate_rejected" | "dependency_not_completed" | "run_cancelled" | "runner_lost" | "step_failed" | "timed_out" | "unknown" | "user_cancelled";
|
|
118
118
|
driverParam: string;
|
|
119
119
|
notNull: false;
|
|
120
120
|
hasDefault: false;
|
|
@@ -303,7 +303,7 @@ export declare const jobExecutions: import("drizzle-orm/pg-core").PgTableWithCol
|
|
|
303
303
|
generated: undefined;
|
|
304
304
|
}, {}, {}>;
|
|
305
305
|
};
|
|
306
|
-
dialect:
|
|
306
|
+
dialect: 'pg';
|
|
307
307
|
}>;
|
|
308
308
|
export type JobExecutionDb = typeof jobExecutions.$inferSelect;
|
|
309
309
|
export type JobExecutionCreateDb = typeof jobExecutions.$inferInsert;
|
|
@@ -212,7 +212,7 @@ export declare const jobListenerEvents: import("drizzle-orm/pg-core").PgTableWit
|
|
|
212
212
|
generated: undefined;
|
|
213
213
|
}, {}, {}>;
|
|
214
214
|
};
|
|
215
|
-
dialect:
|
|
215
|
+
dialect: 'pg';
|
|
216
216
|
}>;
|
|
217
217
|
export type JobListenerEventDb = typeof jobListenerEvents.$inferSelect;
|
|
218
218
|
export type JobListenerEventCreateDb = typeof jobListenerEvents.$inferInsert;
|
package/dist/db/schema/jobs.d.ts
CHANGED
|
@@ -67,7 +67,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
67
67
|
tableName: "jobs";
|
|
68
68
|
dataType: "string";
|
|
69
69
|
columnType: "PgEnumColumn";
|
|
70
|
-
data: "
|
|
70
|
+
data: "listening" | "one_shot";
|
|
71
71
|
driverParam: string;
|
|
72
72
|
notNull: true;
|
|
73
73
|
hasDefault: true;
|
|
@@ -101,7 +101,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
101
101
|
tableName: "jobs";
|
|
102
102
|
dataType: "string";
|
|
103
103
|
columnType: "PgEnumColumn";
|
|
104
|
-
data: "
|
|
104
|
+
data: "cancelled" | "failed" | "pending" | "running" | "skipped" | "succeeded";
|
|
105
105
|
driverParam: string;
|
|
106
106
|
notNull: true;
|
|
107
107
|
hasDefault: true;
|
|
@@ -118,7 +118,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
118
118
|
tableName: "jobs";
|
|
119
119
|
dataType: "string";
|
|
120
120
|
columnType: "PgEnumColumn";
|
|
121
|
-
data: "
|
|
121
|
+
data: "condition_errored" | "condition_false" | "condition_rejected" | "default_gate_rejected" | "dependency_not_completed" | "run_cancelled" | "runner_lost" | "step_failed" | "timed_out" | "unknown" | "user_cancelled";
|
|
122
122
|
driverParam: string;
|
|
123
123
|
notNull: false;
|
|
124
124
|
hasDefault: false;
|
|
@@ -273,7 +273,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
273
273
|
tableName: "jobs";
|
|
274
274
|
dataType: "string";
|
|
275
275
|
columnType: "PgEnumColumn";
|
|
276
|
-
data: "
|
|
276
|
+
data: "cancel" | "finish";
|
|
277
277
|
driverParam: string;
|
|
278
278
|
notNull: false;
|
|
279
279
|
hasDefault: false;
|
|
@@ -341,7 +341,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
341
341
|
tableName: "jobs";
|
|
342
342
|
dataType: "string";
|
|
343
343
|
columnType: "PgEnumColumn";
|
|
344
|
-
data: "
|
|
344
|
+
data: "inactive" | "listening" | "resolved";
|
|
345
345
|
driverParam: string;
|
|
346
346
|
notNull: true;
|
|
347
347
|
hasDefault: true;
|
|
@@ -358,7 +358,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
358
358
|
tableName: "jobs";
|
|
359
359
|
dataType: "string";
|
|
360
360
|
columnType: "PgEnumColumn";
|
|
361
|
-
data: "cancelled" | "
|
|
361
|
+
data: "cancelled" | "max_executions" | "timeout" | "until";
|
|
362
362
|
driverParam: string;
|
|
363
363
|
notNull: false;
|
|
364
364
|
hasDefault: false;
|
|
@@ -534,7 +534,7 @@ export declare const jobs: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
534
534
|
generated: undefined;
|
|
535
535
|
}, {}, {}>;
|
|
536
536
|
};
|
|
537
|
-
dialect:
|
|
537
|
+
dialect: 'pg';
|
|
538
538
|
}>;
|
|
539
539
|
export type JobDb = typeof jobs.$inferSelect;
|
|
540
540
|
export type JobCreateDb = typeof jobs.$inferInsert;
|
|
@@ -93,7 +93,7 @@ export declare const stepAttempts: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
93
93
|
tableName: "step_attempts";
|
|
94
94
|
dataType: "string";
|
|
95
95
|
columnType: "PgEnumColumn";
|
|
96
|
-
data: "
|
|
96
|
+
data: "cancelled" | "failed" | "pending" | "running" | "skipped" | "succeeded";
|
|
97
97
|
driverParam: string;
|
|
98
98
|
notNull: true;
|
|
99
99
|
hasDefault: false;
|
|
@@ -322,7 +322,7 @@ export declare const stepAttempts: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
322
322
|
generated: undefined;
|
|
323
323
|
}, {}, {}>;
|
|
324
324
|
};
|
|
325
|
-
dialect:
|
|
325
|
+
dialect: 'pg';
|
|
326
326
|
}>;
|
|
327
327
|
export type StepAttemptDb = typeof stepAttempts.$inferSelect;
|
|
328
328
|
export type StepAttemptCreateDb = typeof stepAttempts.$inferInsert;
|
|
@@ -98,7 +98,7 @@ export declare const steps: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
98
98
|
tableName: "steps";
|
|
99
99
|
dataType: "string";
|
|
100
100
|
columnType: "PgEnumColumn";
|
|
101
|
-
data: "
|
|
101
|
+
data: "cancelled" | "failed" | "pending" | "running" | "skipped" | "succeeded";
|
|
102
102
|
driverParam: string;
|
|
103
103
|
notNull: true;
|
|
104
104
|
hasDefault: true;
|
|
@@ -115,7 +115,7 @@ export declare const steps: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
115
115
|
tableName: "steps";
|
|
116
116
|
dataType: "string";
|
|
117
117
|
columnType: "PgEnumColumn";
|
|
118
|
-
data: "
|
|
118
|
+
data: "condition_errored" | "condition_rejected" | "default_gate_rejected";
|
|
119
119
|
driverParam: string;
|
|
120
120
|
notNull: false;
|
|
121
121
|
hasDefault: false;
|
|
@@ -151,7 +151,7 @@ export declare const steps: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
151
151
|
tableName: "steps";
|
|
152
152
|
dataType: "string";
|
|
153
153
|
columnType: "PgText";
|
|
154
|
-
data: "
|
|
154
|
+
data: "agent" | "checkout" | "run" | "setup";
|
|
155
155
|
driverParam: string;
|
|
156
156
|
notNull: true;
|
|
157
157
|
hasDefault: false;
|
|
@@ -163,7 +163,7 @@ export declare const steps: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
163
163
|
identity: undefined;
|
|
164
164
|
generated: undefined;
|
|
165
165
|
}, {}, {
|
|
166
|
-
$type: "
|
|
166
|
+
$type: "agent" | "checkout" | "run" | "setup";
|
|
167
167
|
}>;
|
|
168
168
|
config: import("drizzle-orm/pg-core").PgColumn<{
|
|
169
169
|
name: "config";
|
|
@@ -346,7 +346,7 @@ export declare const steps: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
|
346
346
|
generated: undefined;
|
|
347
347
|
}, {}, {}>;
|
|
348
348
|
};
|
|
349
|
-
dialect:
|
|
349
|
+
dialect: 'pg';
|
|
350
350
|
}>;
|
|
351
351
|
export type StepDb = typeof steps.$inferSelect;
|
|
352
352
|
export type StepCreateDb = typeof steps.$inferInsert;
|
|
@@ -61,7 +61,7 @@ export declare const workflowRunAttempts: import("drizzle-orm/pg-core").PgTableW
|
|
|
61
61
|
tableName: "workflow_run_attempts";
|
|
62
62
|
dataType: "string";
|
|
63
63
|
columnType: "PgEnumColumn";
|
|
64
|
-
data: "
|
|
64
|
+
data: "cancelled" | "failed" | "pending" | "running" | "succeeded";
|
|
65
65
|
driverParam: string;
|
|
66
66
|
notNull: true;
|
|
67
67
|
hasDefault: true;
|
|
@@ -78,7 +78,7 @@ export declare const workflowRunAttempts: import("drizzle-orm/pg-core").PgTableW
|
|
|
78
78
|
tableName: "workflow_run_attempts";
|
|
79
79
|
dataType: "string";
|
|
80
80
|
columnType: "PgEnumColumn";
|
|
81
|
-
data: "
|
|
81
|
+
data: "all" | "failed";
|
|
82
82
|
driverParam: string;
|
|
83
83
|
notNull: false;
|
|
84
84
|
hasDefault: false;
|
|
@@ -256,7 +256,7 @@ export declare const workflowRunAttempts: import("drizzle-orm/pg-core").PgTableW
|
|
|
256
256
|
generated: undefined;
|
|
257
257
|
}, {}, {}>;
|
|
258
258
|
};
|
|
259
|
-
dialect:
|
|
259
|
+
dialect: 'pg';
|
|
260
260
|
}>;
|
|
261
261
|
export type WorkflowRunAttemptDb = typeof workflowRunAttempts.$inferSelect;
|
|
262
262
|
export type WorkflowRunAttemptCreateDb = typeof workflowRunAttempts.$inferInsert;
|
|
@@ -37,7 +37,7 @@ export declare const workflowRunCounters: import("drizzle-orm/pg-core").PgTableW
|
|
|
37
37
|
generated: undefined;
|
|
38
38
|
}, {}, {}>;
|
|
39
39
|
};
|
|
40
|
-
dialect:
|
|
40
|
+
dialect: 'pg';
|
|
41
41
|
}>;
|
|
42
42
|
export type WorkflowRunCounterDb = typeof workflowRunCounters.$inferSelect;
|
|
43
43
|
//# sourceMappingURL=workflow-run-counters.d.ts.map
|
|
@@ -129,7 +129,7 @@ export declare const workflowRuns: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
129
129
|
tableName: "workflow_runs";
|
|
130
130
|
dataType: "string";
|
|
131
131
|
columnType: "PgEnumColumn";
|
|
132
|
-
data: "
|
|
132
|
+
data: "cancelled" | "failed" | "pending" | "running" | "succeeded";
|
|
133
133
|
driverParam: string;
|
|
134
134
|
notNull: true;
|
|
135
135
|
hasDefault: true;
|
|
@@ -405,7 +405,7 @@ export declare const workflowRuns: import("drizzle-orm/pg-core").PgTableWithColu
|
|
|
405
405
|
generated: undefined;
|
|
406
406
|
}, {}, {}>;
|
|
407
407
|
};
|
|
408
|
-
dialect:
|
|
408
|
+
dialect: 'pg';
|
|
409
409
|
}>;
|
|
410
410
|
export type WorkflowRunDb = typeof workflowRuns.$inferSelect;
|
|
411
411
|
export type WorkflowRunCreateDb = typeof workflowRuns.$inferInsert;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../../src/db/workflow-runs/job-executions.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,uCAAuC,CAAC;AAGpF,OAAO,KAAK,EAAC,eAAe,EAAC,MAAM,uBAAuB,CAAC;AAC3D,OAAO,KAAK,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,iCAAiC,CAAC;
|
|
1
|
+
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../../src/db/workflow-runs/job-executions.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { readPersistedWorkflowModel } from '@shipfox/api-definitions-dto';
|
|
2
2
|
import { WORKFLOWS_JOB_EXECUTION_TIMED_OUT } from '@shipfox/api-workflows-dto';
|
|
3
3
|
import { and, asc, desc, eq, isNull, notInArray, sql } from 'drizzle-orm';
|
|
4
|
-
import { InterpolationUnresolvableError, JobNotFoundError } from '#core/errors.js';
|
|
4
|
+
import { InterpolationUnresolvableError, JobNotFoundError, JobOutputNotJsonSafeError, JobOutputTooLargeError, JobOutputTooManyEntriesError } from '#core/errors.js';
|
|
5
5
|
import { deriveJobExecutionOutputs } from '#core/job-transition/index.js';
|
|
6
6
|
import { deriveCompletion, isTerminal } from '#core/step-transition/decide-step-transition.js';
|
|
7
7
|
import { recordWorkflowJobExecutionLeaseExpiryResolved, recordWorkflowJobExecutionQueued, recordWorkflowJobExecutionStarted, recordWorkflowJobExecutionStatusChanged, recordWorkflowJobExecutionTimedOut } from '#metrics/instance.js';
|
|
@@ -123,7 +123,9 @@ async function updateJobExecutionStatusAtVersion(tx, params) {
|
|
|
123
123
|
secrets: params.secrets
|
|
124
124
|
});
|
|
125
125
|
} catch (error) {
|
|
126
|
-
if (!(error instanceof InterpolationUnresolvableError))
|
|
126
|
+
if (!(error instanceof InterpolationUnresolvableError) && !(error instanceof JobOutputNotJsonSafeError) && !(error instanceof JobOutputTooLargeError) && !(error instanceof JobOutputTooManyEntriesError)) {
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
127
129
|
status = 'failed';
|
|
128
130
|
statusReason = 'unknown';
|
|
129
131
|
outputs = null;
|