@shipfox/api-runners 12.6.0 → 12.7.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 +8 -0
- package/dist/db/job-executions.d.ts +3 -0
- package/dist/db/job-executions.d.ts.map +1 -1
- package/dist/db/job-executions.js +23 -1
- package/dist/db/job-executions.js.map +1 -1
- package/dist/db/provisioner-tokens.d.ts.map +1 -1
- package/dist/db/provisioner-tokens.js +14 -2
- package/dist/db/provisioner-tokens.js.map +1 -1
- package/dist/db/reservations.d.ts +10 -0
- package/dist/db/reservations.d.ts.map +1 -1
- package/dist/db/reservations.js +137 -17
- package/dist/db/reservations.js.map +1 -1
- package/dist/db/runner-assignments.d.ts.map +1 -1
- package/dist/db/runner-assignments.js +8 -5
- package/dist/db/runner-assignments.js.map +1 -1
- package/dist/db/runner-instances.d.ts +0 -1
- package/dist/db/runner-instances.d.ts.map +1 -1
- package/dist/db/runner-instances.js +85 -100
- package/dist/db/runner-instances.js.map +1 -1
- package/dist/db/runner-states.d.ts +3 -1
- package/dist/db/runner-states.d.ts.map +1 -1
- package/dist/db/runner-states.js +6 -4
- package/dist/db/runner-states.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/db/job-executions.test.ts +119 -0
- package/src/db/job-executions.ts +24 -2
- package/src/db/provisioner-tokens.test.ts +19 -0
- package/src/db/provisioner-tokens.ts +13 -2
- package/src/db/reservations.test.ts +138 -0
- package/src/db/reservations.ts +311 -35
- package/src/db/runner-assignments.test.ts +20 -0
- package/src/db/runner-assignments.ts +6 -7
- package/src/db/runner-instances.test.ts +250 -15
- package/src/db/runner-instances.ts +136 -198
- package/src/db/runner-states.test.ts +16 -0
- package/src/db/runner-states.ts +9 -4
- package/tsconfig.build.tsbuildinfo +1 -1
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
$ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
|
|
2
|
-
Successfully compiled: 104 files with swc (
|
|
3
|
-
2026-08-
|
|
2
|
+
Successfully compiled: 104 files with swc (751.35ms)
|
|
3
|
+
2026-08-10T13:04:49.235Z [INFO] asset workflow-bundle-0c3da2487e29e352d64e.js 3.17 MiB [emitted] [immutable] (name: main)
|
|
4
4
|
orphan modules 33.5 KiB [orphan] 21 modules
|
|
5
5
|
runtime modules 1.13 KiB 5 modules
|
|
6
6
|
modules by path ../../../node_modules/.pnpm/ 970 KiB 196 modules
|
|
@@ -14,6 +14,6 @@ optional modules 30 bytes [optional]
|
|
|
14
14
|
__temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
|
|
15
15
|
__temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
|
|
16
16
|
../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
|
|
17
|
-
webpack 5.107.2 compiled successfully in
|
|
18
|
-
2026-08-
|
|
17
|
+
webpack 5.107.2 compiled successfully in 12344 ms
|
|
18
|
+
2026-08-10T13:04:49.266Z [INFO] Workflow bundle created { size: '3.17MB' }
|
|
19
19
|
/home/runner/work/shipfox/shipfox/libs/api/runners/dist/temporal/workflows/index.js: 3326598 bytes
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @shipfox/api-runners
|
|
2
2
|
|
|
3
|
+
## 12.7.0
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7a5e247: Release runner reservation units when a provisioner reports a terminal runner.
|
|
8
|
+
- Updated dependencies [4df5e37]
|
|
9
|
+
- @shipfox/api-workflows-dto@12.7.0
|
|
10
|
+
|
|
3
11
|
## 12.6.0
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
|
@@ -58,6 +58,9 @@ export declare function claimPendingJobExecution(params: {
|
|
|
58
58
|
/**
|
|
59
59
|
* Releases a job execution's lease when the orchestration workflow finalizes it: deletes the
|
|
60
60
|
* running-job-execution row AND any lingering pending row for the same execution, in one tx.
|
|
61
|
+
* When the deleted lease was the last one for a terminal provider runner, it also releases the
|
|
62
|
+
* runner's reservation in the same runner-owned transaction. Terminal reports and workflow lease
|
|
63
|
+
* finalization remain independently retryable; they do not share a cross-module scope lock.
|
|
61
64
|
* Idempotent (0-row no-op), no token scope (the workflow is authoritative), and
|
|
62
65
|
* emits no event: the workflow already owns the outcome. Sweeping the pending row
|
|
63
66
|
* too closes the at-least-once window where an enqueue retry left an orphan that a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,yBAAyB,EAC/B,MAAM,0BAA0B,CAAC;AAiClC,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@ import { and, arrayContained, asc, count, desc, eq, gt, inArray, isNotNull, isNu
|
|
|
6
6
|
import { EmptyRequiredLabelsError, RunnerSessionExhaustedError, RunningJobExecutionNotFoundError } from '#core/errors.js';
|
|
7
7
|
import { jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, recordJobExecutionQueueTime, recordProviderRunnerActivationToFirstClaim } from '#metrics/instance.js';
|
|
8
8
|
import { db } from './db.js';
|
|
9
|
+
import { releaseTerminalRunnerInstanceReservationsByIds } from './reservations.js';
|
|
9
10
|
import { runnersOutbox } from './schema/outbox.js';
|
|
10
11
|
import { pendingJobExecutions } from './schema/pending-job-executions.js';
|
|
11
12
|
import { providerRunners } from './schema/runner-instances.js';
|
|
@@ -229,6 +230,9 @@ async function touchRunnerSessionLiveness(params) {
|
|
|
229
230
|
/**
|
|
230
231
|
* Releases a job execution's lease when the orchestration workflow finalizes it: deletes the
|
|
231
232
|
* running-job-execution row AND any lingering pending row for the same execution, in one tx.
|
|
233
|
+
* When the deleted lease was the last one for a terminal provider runner, it also releases the
|
|
234
|
+
* runner's reservation in the same runner-owned transaction. Terminal reports and workflow lease
|
|
235
|
+
* finalization remain independently retryable; they do not share a cross-module scope lock.
|
|
232
236
|
* Idempotent (0-row no-op), no token scope (the workflow is authoritative), and
|
|
233
237
|
* emits no event: the workflow already owns the outcome. Sweeping the pending row
|
|
234
238
|
* too closes the at-least-once window where an enqueue retry left an orphan that a
|
|
@@ -241,7 +245,25 @@ async function touchRunnerSessionLiveness(params) {
|
|
|
241
245
|
// claim picking up an orphan pending row for this same job execution would otherwise
|
|
242
246
|
// deadlock against the reverse order here.
|
|
243
247
|
await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));
|
|
244
|
-
await tx.delete(runningJobExecutions).where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId))
|
|
248
|
+
const deletedRunningRows = await tx.delete(runningJobExecutions).where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId)).returning({
|
|
249
|
+
workspaceId: runningJobExecutions.workspaceId,
|
|
250
|
+
provisionerId: runningJobExecutions.provisionerId,
|
|
251
|
+
providerRunnerId: runningJobExecutions.providerRunnerId
|
|
252
|
+
});
|
|
253
|
+
const deletedRunningRow = deletedRunningRows[0];
|
|
254
|
+
if (deletedRunningRow?.provisionerId && deletedRunningRow.providerRunnerId) {
|
|
255
|
+
await releaseTerminalRunnerInstanceReservationsByIds(tx, {
|
|
256
|
+
workspaceId: null,
|
|
257
|
+
provisionerId: deletedRunningRow.provisionerId,
|
|
258
|
+
providerRunnerIds: [
|
|
259
|
+
deletedRunningRow.providerRunnerId
|
|
260
|
+
],
|
|
261
|
+
requireUnlinkedSession: false,
|
|
262
|
+
// Lock and re-check the runner row locally so terminal reporting remains retryable
|
|
263
|
+
// without a workflow/runner scope lock.
|
|
264
|
+
requireTerminalState: false
|
|
265
|
+
});
|
|
266
|
+
}
|
|
245
267
|
});
|
|
246
268
|
}
|
|
247
269
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/job-executions.ts"],"sourcesContent":["import {\n RUNNER_JOB_CLAIMED,\n RUNNER_JOB_LEASE_EXPIRED,\n RUNNER_JOB_QUEUED,\n type RunnersEventMap,\n type RunnerToolCapabilitiesDto,\n} from '@shipfox/api-runners-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContained,\n asc,\n count,\n desc,\n eq,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport {\n EmptyRequiredLabelsError,\n RunnerSessionExhaustedError,\n RunningJobExecutionNotFoundError,\n} from '#core/errors.js';\nimport {\n type JobExecutionQueueTimeObservation,\n jobExecutionEnqueuedCount,\n jobExecutionLeaseExpiredCount,\n type ProviderRunnerLifecycleObservation,\n recordJobExecutionQueueTime,\n recordProviderRunnerActivationToFirstClaim,\n} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nconst runnerJobExecutionLockPrefix = 'runners_job_execution:';\n\nasync function lockJobExecution(tx: Tx, jobExecutionId: string): Promise<void> {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`${runnerJobExecutionLockPrefix}${jobExecutionId}`}))`,\n );\n}\n\nexport interface EnqueueJobExecutionParams {\n workspaceId: string;\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n}\n\nexport async function getWorkspaceJobCounts(params: {\n workspaceIds: string[];\n}): Promise<Array<{workspaceId: string; queued: number; running: number}>> {\n const [pendingRows, runningRows] = await Promise.all([\n db()\n .select({workspaceId: pendingJobExecutions.workspaceId, count: count()})\n .from(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.workspaceId, params.workspaceIds))\n .groupBy(pendingJobExecutions.workspaceId),\n db()\n .select({workspaceId: runningJobExecutions.workspaceId, count: count()})\n .from(runningJobExecutions)\n .where(inArray(runningJobExecutions.workspaceId, params.workspaceIds))\n .groupBy(runningJobExecutions.workspaceId),\n ]);\n\n const queuedByWorkspace = new Map(pendingRows.map((row) => [row.workspaceId, Number(row.count)]));\n const runningByWorkspace = new Map(\n runningRows.map((row) => [row.workspaceId, Number(row.count)]),\n );\n\n return params.workspaceIds.map((workspaceId) => ({\n workspaceId,\n queued: queuedByWorkspace.get(workspaceId) ?? 0,\n running: runningByWorkspace.get(workspaceId) ?? 0,\n }));\n}\n\n// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in\n// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity at-least-once, so a\n// unique-violation throw on a retry-after-lost-result would permanently fail a healthy execution.\n// The per-execution advisory lock serializes retries with lease expiry/reconciliation, and the\n// durable lease-expired event prevents a retry from re-queueing an execution already reaped.\nexport async function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void> {\n const requiredLabels = [...canonicalizeLabels(params.requiredLabels)];\n if (requiredLabels.length === 0) throw new EmptyRequiredLabelsError();\n\n const enqueued = await db().transaction(async (tx) => {\n await lockJobExecution(tx, params.jobExecutionId);\n\n const [leaseExpired] = await tx\n .select({id: runnersOutbox.id})\n .from(runnersOutbox)\n .where(\n and(\n eq(runnersOutbox.eventType, RUNNER_JOB_LEASE_EXPIRED),\n sql`${runnersOutbox.payload}->>'jobExecutionId' = ${params.jobExecutionId}`,\n ),\n )\n .limit(1);\n if (leaseExpired) return false;\n\n const [inserted] = await tx\n .insert(pendingJobExecutions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n projectId: params.projectId,\n requiredLabels,\n })\n .onConflictDoNothing({target: pendingJobExecutions.jobExecutionId})\n .returning({createdAt: pendingJobExecutions.createdAt});\n\n // A retry that hits the conflict inserts nothing: the first enqueue already\n // emitted the queued event (durably, in the outbox), so re-emitting would\n // only add a redundant row the subscriber coalesces away. Skip it.\n if (!inserted) return false;\n\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_QUEUED,\n payload: {\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n queuedAt: inserted.createdAt.toISOString(),\n },\n });\n return true;\n });\n\n if (enqueued) jobExecutionEnqueuedCount.add(1);\n}\n\nexport interface ClaimedJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n}\n\nexport interface ActiveRunningJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n runnerSessionId: string;\n provisionerId: string | null;\n providerRunnerId: string | null;\n requiredLabels: string[];\n runnerLabels: string[];\n startedAt: Date;\n lastHeartbeatAt: Date;\n}\n\nexport interface RunnerInstanceBoundJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport async function claimPendingJobExecution(params: {\n workspaceId: string;\n runnerSessionId: string;\n sessionLabels: string[];\n maxClaims: number | null;\n runnerSessionLivenessThrottleSeconds: number;\n}): Promise<ClaimedJobExecution | null> {\n await touchRunnerSessionLiveness({\n workspaceId: params.workspaceId,\n runnerSessionId: params.runnerSessionId,\n throttleSeconds: params.runnerSessionLivenessThrottleSeconds,\n });\n\n if (params.sessionLabels.length === 0) return null;\n\n let activationToFirstClaimObservation: ProviderRunnerLifecycleObservation | null = null;\n let queueTimeObservation: JobExecutionQueueTimeObservation | null = null;\n const result = await db().transaction(async (tx) => {\n let provisionerId: string | null = null;\n let providerRunnerId: string | null = null;\n let runnerInstanceId: string | null = null;\n\n if (params.maxClaims !== null) {\n const [session] = await tx\n .select({\n maxClaims: runnerSessions.maxClaims,\n claimsUsed: runnerSessions.claimsUsed,\n revokedAt: runnerSessions.revokedAt,\n runnerInstanceId: runnerSessions.runnerInstanceId,\n provisionerId: runnerSessions.provisionerId,\n providerRunnerId: runnerSessions.providerRunnerId,\n })\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n if (\n !session ||\n session.revokedAt ||\n session.maxClaims === null ||\n session.claimsUsed >= session.maxClaims\n ) {\n throw new RunnerSessionExhaustedError(params.runnerSessionId);\n }\n\n // Ephemeral sessions are the only capped sessions, and the DB check keeps\n // their provisioned-runner link present as a pair.\n runnerInstanceId = session.runnerInstanceId;\n provisionerId = session.provisionerId;\n providerRunnerId = session.providerRunnerId;\n }\n\n // `id` is a uuidv7 (time-ordered), so it is a deterministic FIFO tiebreaker\n // for rows sharing a created_at within a batch. Lock only the FIFO candidate before\n // attempting its execution advisory lock; putting pg_try_advisory_xact_lock in this\n // predicate would evaluate it while scanning and temporarily lock many queue entries.\n const candidate = tx\n .select()\n .from(pendingJobExecutions)\n .where(\n and(\n eq(pendingJobExecutions.workspaceId, params.workspaceId),\n arrayContained(pendingJobExecutions.requiredLabels, params.sessionLabels),\n ),\n )\n .orderBy(asc(pendingJobExecutions.createdAt), asc(pendingJobExecutions.id))\n .limit(1)\n .for('update', {skipLocked: true})\n .as('pending_candidate');\n\n const [row] = await tx\n .select()\n .from(candidate)\n .where(\n sql`\n pg_try_advisory_xact_lock(\n hashtext(${runnerJobExecutionLockPrefix} || ${candidate.jobExecutionId}::text)\n )\n `,\n );\n\n if (!row) return null;\n\n await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.id, row.id));\n\n // An enqueue retry that lands after a prior claim can leave an orphan pending\n // row whose jobExecutionId is already in `runners_running_jobs`. Insert-or-skip\n // on the jobExecutionId unique constraint: when the job execution is already running\n // the insert touches no row, so we commit the orphan's deletion and return\n // null rather than let the unique violation roll the claim back into a poison\n // loop. The runner just re-polls for a real job execution.\n const inserted = await tx\n .insert(runningJobExecutions)\n .values({\n workspaceId: row.workspaceId,\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n runnerSessionId: params.runnerSessionId,\n provisionerId,\n providerRunnerId,\n requiredLabels: row.requiredLabels,\n runnerLabels: params.sessionLabels,\n })\n .onConflictDoNothing({target: runningJobExecutions.jobExecutionId})\n .returning({claimedAt: runningJobExecutions.startedAt});\n\n const claimed = inserted[0];\n if (!claimed) return null;\n\n queueTimeObservation = {\n durationMilliseconds: claimed.claimedAt.getTime() - row.createdAt.getTime(),\n provider: null,\n launchKind: params.maxClaims === null ? 'manual' : 'unknown',\n };\n\n const runnerInstanceCondition = runnerInstanceId\n ? eq(providerRunners.id, runnerInstanceId)\n : provisionerId && providerRunnerId\n ? and(\n eq(providerRunners.provisionerId, provisionerId),\n eq(providerRunners.providerRunnerId, providerRunnerId),\n )\n : null;\n if (runnerInstanceCondition) {\n const [claimedRunner] = await tx\n .update(providerRunners)\n .set({\n firstClaimedAt: sql`coalesce(${providerRunners.firstClaimedAt}, ${claimed.claimedAt})`,\n updatedAt: sql`now()`,\n })\n .where(runnerInstanceCondition)\n .returning({\n firstClaimedAt: providerRunners.firstClaimedAt,\n isFirstClaim: sql<boolean>`${providerRunners.firstClaimedAt} = ${claimed.claimedAt}`,\n provider: providerRunners.providerKind,\n launchKind: providerRunners.launchKind,\n runnerInstanceId: providerRunners.id,\n sessionCreatedAtEpochMs: sql<number | null>`(\n select extract(epoch from ${runnerSessions.createdAt})::double precision * 1000\n from ${runnerSessions}\n where ${runnerSessions.id} = ${params.runnerSessionId}\n )`,\n });\n if (claimedRunner && queueTimeObservation) {\n queueTimeObservation.provider = claimedRunner.provider;\n queueTimeObservation.launchKind = claimedRunner.launchKind;\n }\n if (\n claimedRunner?.isFirstClaim &&\n claimedRunner.firstClaimedAt !== null &&\n claimedRunner.sessionCreatedAtEpochMs !== null &&\n claimedRunner.sessionCreatedAtEpochMs !== undefined\n )\n activationToFirstClaimObservation = {\n durationMilliseconds:\n claimedRunner.firstClaimedAt.getTime() - claimedRunner.sessionCreatedAtEpochMs,\n provider: claimedRunner.provider,\n launchKind: claimedRunner.launchKind,\n runnerInstanceId: claimedRunner.runnerInstanceId,\n };\n }\n\n if (params.maxClaims !== null) {\n await tx\n .update(runnerSessions)\n .set({claimsUsed: sql`${runnerSessions.claimsUsed} + 1`, updatedAt: sql`now()`})\n .where(eq(runnerSessions.id, params.runnerSessionId));\n }\n\n // The running-row insert is the runner claiming the job execution. Emit in the same tx; the\n // payload carries the row's own claim instant so a consumer records the true time,\n // not the outbox drain time.\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_CLAIMED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n claimedAt: claimed.claimedAt.toISOString(),\n },\n });\n\n return {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n };\n });\n if (queueTimeObservation) recordJobExecutionQueueTime(queueTimeObservation);\n if (activationToFirstClaimObservation)\n recordProviderRunnerActivationToFirstClaim(activationToFirstClaimObservation);\n return result;\n}\n\nasync function touchRunnerSessionLiveness(params: {\n workspaceId: string;\n runnerSessionId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(runnerSessions)\n .set({updatedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.id, params.runnerSessionId),\n eq(runnerSessions.workspaceId, params.workspaceId),\n sql`${runnerSessions.updatedAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n );\n}\n\n/**\n * Releases a job execution's lease when the orchestration workflow finalizes it: deletes the\n * running-job-execution row AND any lingering pending row for the same execution, in one tx.\n * Idempotent (0-row no-op), no token scope (the workflow is authoritative), and\n * emits no event: the workflow already owns the outcome. Sweeping the pending row\n * too closes the at-least-once window where an enqueue retry left an orphan that a\n * later claim would otherwise pick up for an already-finished job execution.\n */\nexport async function releaseJobExecution(params: {jobExecutionId: string}): Promise<void> {\n await db().transaction(async (tx) => {\n await lockJobExecution(tx, params.jobExecutionId);\n\n // Delete pending before running to match `claimPendingJobExecution`'s lock-acquisition\n // order (it locks the pending row first, then the running row). A concurrent\n // claim picking up an orphan pending row for this same job execution would otherwise\n // deadlock against the reverse order here.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .delete(runningJobExecutions)\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\n/**\n * Reaps stale leases (bounded by `limit`), emitting one\n * `runners.job.lease_expired` event per reaped job execution.\n *\n * The cutoff is re-checked in the DELETE, not just the locking subquery, so a\n * heartbeat landing mid-call spares the live row. Each reaped execution also sweeps its\n * pending row: a failed best-effort `releaseJobExecution` would otherwise leave an orphan\n * that a later claim re-runs as an already-finished job execution.\n *\n * Locks pending-then-running to match `claimPendingJobExecution`, `releaseJobExecution`, and\n * `reconcileTerminalJobExecution`. The stale candidate scan intentionally does not lock running\n * rows first; the running-row DELETE re-checks the stale predicate after the pending-row sweep.\n */\nexport async function expireStuckJobExecutions(params: {\n thresholdSeconds: number;\n noFirstHeartbeatGraceSeconds: number;\n limit?: number;\n}): Promise<\n Array<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n }>\n> {\n const reaped = await db().transaction(async (tx) => {\n const heartbeatCutoff = sql`now() - (${params.thresholdSeconds} || ' seconds')::interval`;\n const firstHeartbeatCutoff = sql`now() - (${params.noFirstHeartbeatGraceSeconds} || ' seconds')::interval`;\n const stalePredicate = or(\n and(\n isNull(runningJobExecutions.firstHeartbeatAt),\n lte(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n lt(runningJobExecutions.startedAt, firstHeartbeatCutoff),\n ),\n and(\n or(\n isNotNull(runningJobExecutions.firstHeartbeatAt),\n gt(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n ),\n lt(runningJobExecutions.lastHeartbeatAt, heartbeatCutoff),\n ),\n );\n\n const staleRows = await tx\n .select({\n id: runningJobExecutions.id,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n })\n .from(runningJobExecutions)\n .where(\n and(\n stalePredicate,\n sql`\n pg_try_advisory_xact_lock(\n hashtext(${runnerJobExecutionLockPrefix} || ${runningJobExecutions.jobExecutionId}::text)\n )\n `,\n ),\n )\n .orderBy(\n asc(\n sql`CASE WHEN ${runningJobExecutions.firstHeartbeatAt} IS NULL AND ${runningJobExecutions.lastHeartbeatAt} <= ${runningJobExecutions.startedAt} THEN ${runningJobExecutions.startedAt} ELSE ${runningJobExecutions.lastHeartbeatAt} END`,\n ),\n asc(runningJobExecutions.id),\n )\n .limit(params.limit ?? 100);\n\n if (staleRows.length === 0) return [];\n\n const staleIds = staleRows.map((row) => row.id);\n const staleJobExecutionIds = staleRows.map((row) => row.jobExecutionId);\n\n // Sweep pending rows first so this transaction cannot hold a running-row lock while waiting\n // for a pending-row lock held by reconciliation or a claim of an orphan pending row. The\n // advisory lock acquired in the candidate scan also makes enqueue retries wait until this\n // transaction has either reaped the execution or released its lock without selecting it.\n await tx\n .delete(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.jobExecutionId, staleJobExecutionIds));\n\n const deleted = await tx\n .delete(runningJobExecutions)\n .where(and(inArray(runningJobExecutions.id, staleIds), stalePredicate))\n .returning({\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n });\n\n if (deleted.length === 0) return [];\n\n await writeOutboxEvents<RunnersEventMap>(\n tx,\n runnersOutbox,\n deleted.map((row) => ({\n type: RUNNER_JOB_LEASE_EXPIRED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n },\n })),\n );\n\n return deleted;\n });\n\n if (reaped.length > 0) jobExecutionLeaseExpiredCount.add(reaped.length);\n\n return reaped;\n}\n\nexport async function getJobExecutionQueueDepth(): Promise<{\n pendingJobExecutions: number;\n runningJobExecutions: number;\n}> {\n const [pending] = await db().select({value: count()}).from(pendingJobExecutions);\n const [running] = await db().select({value: count()}).from(runningJobExecutions);\n return {\n pendingJobExecutions: pending?.value ?? 0,\n runningJobExecutions: running?.value ?? 0,\n };\n}\n\nexport async function listActiveRunningJobExecutions(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<ActiveRunningJobExecution[]> {\n return await db()\n .select({\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n projectId: runningJobExecutions.projectId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n provisionerId: runningJobExecutions.provisionerId,\n providerRunnerId: runningJobExecutions.providerRunnerId,\n requiredLabels: runningJobExecutions.requiredLabels,\n runnerLabels: runningJobExecutions.runnerLabels,\n startedAt: runningJobExecutions.startedAt,\n lastHeartbeatAt: runningJobExecutions.lastHeartbeatAt,\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n sql`${runningJobExecutions.lastHeartbeatAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(runningJobExecutions.lastHeartbeatAt), desc(runningJobExecutions.id))\n .limit(params.limit ?? 1000);\n}\n\nexport async function listRunningJobExecutionsByRunnerInstanceTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n providerRunnerIds: string[];\n },\n): Promise<RunnerInstanceBoundJobExecution[]> {\n if (params.providerRunnerIds.length === 0) return [];\n\n const duplicateRows = await tx\n .select({\n providerRunnerId: runningJobExecutions.providerRunnerId,\n count: count(),\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n inArray(runningJobExecutions.providerRunnerId, params.providerRunnerIds),\n ),\n )\n .groupBy(runningJobExecutions.providerRunnerId)\n .having(sql`count(*) > 1`);\n\n const duplicateRunnerInstanceIds = duplicateRows.flatMap((row) =>\n row.providerRunnerId ? [row.providerRunnerId] : [],\n );\n if (duplicateRunnerInstanceIds.length > 0) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: duplicateRunnerInstanceIds,\n },\n 'multiple running job executions are bound to the same provisioned runner',\n );\n }\n\n const result = await tx.execute<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date | string;\n lastHeartbeatAt: Date | string;\n cancellationRequestedAt: Date | string | null;\n }>(sql`\n SELECT DISTINCT ON (${runningJobExecutions.providerRunnerId})\n ${runningJobExecutions.workflowRunId} AS \"workflowRunId\",\n ${runningJobExecutions.workflowRunAttemptId} AS \"workflowRunAttemptId\",\n ${runningJobExecutions.jobId} AS \"jobId\",\n ${runningJobExecutions.jobExecutionId} AS \"jobExecutionId\",\n ${runningJobExecutions.providerRunnerId} AS \"providerRunnerId\",\n ${runningJobExecutions.startedAt} AS \"startedAt\",\n ${runningJobExecutions.lastHeartbeatAt} AS \"lastHeartbeatAt\",\n ${runningJobExecutions.cancellationRequestedAt} AS \"cancellationRequestedAt\"\n FROM ${runningJobExecutions}\n WHERE\n ${runningJobExecutions.workspaceId} = ${params.workspaceId}\n AND ${runningJobExecutions.provisionerId} = ${params.provisionerId}\n AND ${runningJobExecutions.providerRunnerId} IN (${sql.join(\n params.providerRunnerIds.map((providerRunnerId) => sql`${providerRunnerId}`),\n sql`, `,\n )})\n ORDER BY ${runningJobExecutions.providerRunnerId}, ${runningJobExecutions.startedAt} DESC, ${runningJobExecutions.jobExecutionId} DESC\n `);\n\n return result.rows.map((row) => ({\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n providerRunnerId: row.providerRunnerId,\n startedAt: toDate(row.startedAt),\n lastHeartbeatAt: toDate(row.lastHeartbeatAt),\n cancellationRequestedAt: row.cancellationRequestedAt\n ? toDate(row.cancellationRequestedAt)\n : null,\n }));\n}\n\nfunction toDate(value: Date | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\nexport async function isJobLeaseActive(params: {\n jobId?: string;\n jobExecutionId: string;\n runnerSessionId: string;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n params.jobId === undefined ? undefined : eq(runningJobExecutions.jobId, params.jobId),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nexport async function recordHeartbeat(params: {\n jobExecutionId: string;\n runnerSessionId: string;\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<{\n cancellationRequested: boolean;\n previousToolCapabilities: RunnerToolCapabilitiesDto | null;\n currentToolCapabilities: RunnerToolCapabilitiesDto | null;\n runningJobExecution: {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n workspaceId: string;\n runnerSessionId: string;\n };\n}> {\n const result = await db().transaction(async (tx) => {\n const updated = await tx\n .update(runningJobExecutions)\n .set({\n firstHeartbeatAt: sql`COALESCE(${runningJobExecutions.firstHeartbeatAt}, now())`,\n lastHeartbeatAt: sql`now()`,\n })\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n ),\n )\n .returning({\n cancellationRequestedAt: runningJobExecutions.cancellationRequestedAt,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n projectId: runningJobExecutions.projectId,\n workspaceId: runningJobExecutions.workspaceId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n });\n\n const row = updated[0];\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n\n const [previous] = await tx\n .select({toolCapabilities: runnerSessions.toolCapabilities})\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n const [session] = await tx\n .update(runnerSessions)\n .set({\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n updatedAt: sql`now()`,\n })\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .returning({toolCapabilities: runnerSessions.toolCapabilities});\n\n return {\n row,\n previousToolCapabilities: previous?.toolCapabilities ?? null,\n currentToolCapabilities: session?.toolCapabilities ?? null,\n };\n });\n\n const row = result.row;\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n return {\n cancellationRequested: row.cancellationRequestedAt !== null,\n previousToolCapabilities: result.previousToolCapabilities,\n currentToolCapabilities: result.currentToolCapabilities,\n runningJobExecution: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n workspaceId: row.workspaceId,\n runnerSessionId: row.runnerSessionId,\n },\n };\n}\n\n/**\n * Reconciles a terminal job execution with runner state in one transaction: removes its pending\n * queue row and requests cancellation on its running lease, if either exists. The operation is\n * idempotent and preserves the first cancellation-request timestamp.\n */\nexport async function reconcileTerminalJobExecution(params: {\n jobExecutionId: string;\n}): Promise<void> {\n await db().transaction(async (tx) => {\n await lockJobExecution(tx, params.jobExecutionId);\n\n // Delete pending before updating running to match claim/release lock order. Claim locks\n // pending rows with SKIP LOCKED before inserting the running lease, so this ordering makes\n // a concurrent terminal reconciliation either win before claim or cancel the new lease.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\nexport async function cancelRunnerJobs(params: {jobIds: string[]}): Promise<void> {\n if (params.jobIds.length === 0) return;\n\n await db().transaction(async (tx) => {\n await tx.delete(pendingJobExecutions).where(inArray(pendingJobExecutions.jobId, params.jobIds));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(inArray(runningJobExecutions.jobId, params.jobIds));\n });\n}\n"],"names":["RUNNER_JOB_CLAIMED","RUNNER_JOB_LEASE_EXPIRED","RUNNER_JOB_QUEUED","logger","writeOutboxEvent","writeOutboxEvents","canonicalizeLabels","and","arrayContained","asc","count","desc","eq","gt","inArray","isNotNull","isNull","lt","lte","or","sql","EmptyRequiredLabelsError","RunnerSessionExhaustedError","RunningJobExecutionNotFoundError","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","recordJobExecutionQueueTime","recordProviderRunnerActivationToFirstClaim","db","runnersOutbox","pendingJobExecutions","providerRunners","runnerSessions","runningJobExecutions","runnerJobExecutionLockPrefix","lockJobExecution","tx","jobExecutionId","execute","getWorkspaceJobCounts","params","pendingRows","runningRows","Promise","all","select","workspaceId","from","where","workspaceIds","groupBy","queuedByWorkspace","Map","map","row","Number","runningByWorkspace","queued","get","running","enqueueJobExecution","requiredLabels","length","enqueued","transaction","leaseExpired","id","eventType","payload","limit","inserted","insert","values","workflowRunId","workflowRunAttemptId","jobId","projectId","onConflictDoNothing","target","returning","createdAt","type","queuedAt","toISOString","add","claimPendingJobExecution","touchRunnerSessionLiveness","runnerSessionId","throttleSeconds","runnerSessionLivenessThrottleSeconds","sessionLabels","activationToFirstClaimObservation","queueTimeObservation","result","provisionerId","providerRunnerId","runnerInstanceId","maxClaims","session","claimsUsed","revokedAt","for","candidate","orderBy","skipLocked","as","delete","runnerLabels","claimedAt","startedAt","claimed","durationMilliseconds","getTime","provider","launchKind","runnerInstanceCondition","claimedRunner","update","set","firstClaimedAt","updatedAt","isFirstClaim","providerKind","sessionCreatedAtEpochMs","undefined","releaseJobExecution","expireStuckJobExecutions","reaped","heartbeatCutoff","thresholdSeconds","firstHeartbeatCutoff","noFirstHeartbeatGraceSeconds","stalePredicate","firstHeartbeatAt","lastHeartbeatAt","staleRows","staleIds","staleJobExecutionIds","deleted","getJobExecutionQueueDepth","pending","value","listActiveRunningJobExecutions","windowSeconds","listRunningJobExecutionsByRunnerInstanceTx","providerRunnerIds","duplicateRows","having","duplicateRunnerInstanceIds","flatMap","warn","cancellationRequestedAt","join","rows","toDate","Date","isJobLeaseActive","recordHeartbeat","updated","previous","toolCapabilities","toolCapabilitiesReportedAt","previousToolCapabilities","currentToolCapabilities","cancellationRequested","runningJobExecution","reconcileTerminalJobExecution","cancelRunnerJobs","jobIds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/job-executions.ts"],"sourcesContent":["import {\n RUNNER_JOB_CLAIMED,\n RUNNER_JOB_LEASE_EXPIRED,\n RUNNER_JOB_QUEUED,\n type RunnersEventMap,\n type RunnerToolCapabilitiesDto,\n} from '@shipfox/api-runners-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContained,\n asc,\n count,\n desc,\n eq,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport {\n EmptyRequiredLabelsError,\n RunnerSessionExhaustedError,\n RunningJobExecutionNotFoundError,\n} from '#core/errors.js';\nimport {\n type JobExecutionQueueTimeObservation,\n jobExecutionEnqueuedCount,\n jobExecutionLeaseExpiredCount,\n type ProviderRunnerLifecycleObservation,\n recordJobExecutionQueueTime,\n recordProviderRunnerActivationToFirstClaim,\n} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {releaseTerminalRunnerInstanceReservationsByIds} from './reservations.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nconst runnerJobExecutionLockPrefix = 'runners_job_execution:';\n\nasync function lockJobExecution(tx: Tx, jobExecutionId: string): Promise<void> {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`${runnerJobExecutionLockPrefix}${jobExecutionId}`}))`,\n );\n}\n\nexport interface EnqueueJobExecutionParams {\n workspaceId: string;\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n}\n\nexport async function getWorkspaceJobCounts(params: {\n workspaceIds: string[];\n}): Promise<Array<{workspaceId: string; queued: number; running: number}>> {\n const [pendingRows, runningRows] = await Promise.all([\n db()\n .select({workspaceId: pendingJobExecutions.workspaceId, count: count()})\n .from(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.workspaceId, params.workspaceIds))\n .groupBy(pendingJobExecutions.workspaceId),\n db()\n .select({workspaceId: runningJobExecutions.workspaceId, count: count()})\n .from(runningJobExecutions)\n .where(inArray(runningJobExecutions.workspaceId, params.workspaceIds))\n .groupBy(runningJobExecutions.workspaceId),\n ]);\n\n const queuedByWorkspace = new Map(pendingRows.map((row) => [row.workspaceId, Number(row.count)]));\n const runningByWorkspace = new Map(\n runningRows.map((row) => [row.workspaceId, Number(row.count)]),\n );\n\n return params.workspaceIds.map((workspaceId) => ({\n workspaceId,\n queued: queuedByWorkspace.get(workspaceId) ?? 0,\n running: runningByWorkspace.get(workspaceId) ?? 0,\n }));\n}\n\n// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in\n// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity at-least-once, so a\n// unique-violation throw on a retry-after-lost-result would permanently fail a healthy execution.\n// The per-execution advisory lock serializes retries with lease expiry/reconciliation, and the\n// durable lease-expired event prevents a retry from re-queueing an execution already reaped.\nexport async function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void> {\n const requiredLabels = [...canonicalizeLabels(params.requiredLabels)];\n if (requiredLabels.length === 0) throw new EmptyRequiredLabelsError();\n\n const enqueued = await db().transaction(async (tx) => {\n await lockJobExecution(tx, params.jobExecutionId);\n\n const [leaseExpired] = await tx\n .select({id: runnersOutbox.id})\n .from(runnersOutbox)\n .where(\n and(\n eq(runnersOutbox.eventType, RUNNER_JOB_LEASE_EXPIRED),\n sql`${runnersOutbox.payload}->>'jobExecutionId' = ${params.jobExecutionId}`,\n ),\n )\n .limit(1);\n if (leaseExpired) return false;\n\n const [inserted] = await tx\n .insert(pendingJobExecutions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n projectId: params.projectId,\n requiredLabels,\n })\n .onConflictDoNothing({target: pendingJobExecutions.jobExecutionId})\n .returning({createdAt: pendingJobExecutions.createdAt});\n\n // A retry that hits the conflict inserts nothing: the first enqueue already\n // emitted the queued event (durably, in the outbox), so re-emitting would\n // only add a redundant row the subscriber coalesces away. Skip it.\n if (!inserted) return false;\n\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_QUEUED,\n payload: {\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n queuedAt: inserted.createdAt.toISOString(),\n },\n });\n return true;\n });\n\n if (enqueued) jobExecutionEnqueuedCount.add(1);\n}\n\nexport interface ClaimedJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n}\n\nexport interface ActiveRunningJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n runnerSessionId: string;\n provisionerId: string | null;\n providerRunnerId: string | null;\n requiredLabels: string[];\n runnerLabels: string[];\n startedAt: Date;\n lastHeartbeatAt: Date;\n}\n\nexport interface RunnerInstanceBoundJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport async function claimPendingJobExecution(params: {\n workspaceId: string;\n runnerSessionId: string;\n sessionLabels: string[];\n maxClaims: number | null;\n runnerSessionLivenessThrottleSeconds: number;\n}): Promise<ClaimedJobExecution | null> {\n await touchRunnerSessionLiveness({\n workspaceId: params.workspaceId,\n runnerSessionId: params.runnerSessionId,\n throttleSeconds: params.runnerSessionLivenessThrottleSeconds,\n });\n\n if (params.sessionLabels.length === 0) return null;\n\n let activationToFirstClaimObservation: ProviderRunnerLifecycleObservation | null = null;\n let queueTimeObservation: JobExecutionQueueTimeObservation | null = null;\n const result = await db().transaction(async (tx) => {\n let provisionerId: string | null = null;\n let providerRunnerId: string | null = null;\n let runnerInstanceId: string | null = null;\n\n if (params.maxClaims !== null) {\n const [session] = await tx\n .select({\n maxClaims: runnerSessions.maxClaims,\n claimsUsed: runnerSessions.claimsUsed,\n revokedAt: runnerSessions.revokedAt,\n runnerInstanceId: runnerSessions.runnerInstanceId,\n provisionerId: runnerSessions.provisionerId,\n providerRunnerId: runnerSessions.providerRunnerId,\n })\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n if (\n !session ||\n session.revokedAt ||\n session.maxClaims === null ||\n session.claimsUsed >= session.maxClaims\n ) {\n throw new RunnerSessionExhaustedError(params.runnerSessionId);\n }\n\n // Ephemeral sessions are the only capped sessions, and the DB check keeps\n // their provisioned-runner link present as a pair.\n runnerInstanceId = session.runnerInstanceId;\n provisionerId = session.provisionerId;\n providerRunnerId = session.providerRunnerId;\n }\n\n // `id` is a uuidv7 (time-ordered), so it is a deterministic FIFO tiebreaker\n // for rows sharing a created_at within a batch. Lock only the FIFO candidate before\n // attempting its execution advisory lock; putting pg_try_advisory_xact_lock in this\n // predicate would evaluate it while scanning and temporarily lock many queue entries.\n const candidate = tx\n .select()\n .from(pendingJobExecutions)\n .where(\n and(\n eq(pendingJobExecutions.workspaceId, params.workspaceId),\n arrayContained(pendingJobExecutions.requiredLabels, params.sessionLabels),\n ),\n )\n .orderBy(asc(pendingJobExecutions.createdAt), asc(pendingJobExecutions.id))\n .limit(1)\n .for('update', {skipLocked: true})\n .as('pending_candidate');\n\n const [row] = await tx\n .select()\n .from(candidate)\n .where(\n sql`\n pg_try_advisory_xact_lock(\n hashtext(${runnerJobExecutionLockPrefix} || ${candidate.jobExecutionId}::text)\n )\n `,\n );\n\n if (!row) return null;\n\n await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.id, row.id));\n\n // An enqueue retry that lands after a prior claim can leave an orphan pending\n // row whose jobExecutionId is already in `runners_running_jobs`. Insert-or-skip\n // on the jobExecutionId unique constraint: when the job execution is already running\n // the insert touches no row, so we commit the orphan's deletion and return\n // null rather than let the unique violation roll the claim back into a poison\n // loop. The runner just re-polls for a real job execution.\n const inserted = await tx\n .insert(runningJobExecutions)\n .values({\n workspaceId: row.workspaceId,\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n runnerSessionId: params.runnerSessionId,\n provisionerId,\n providerRunnerId,\n requiredLabels: row.requiredLabels,\n runnerLabels: params.sessionLabels,\n })\n .onConflictDoNothing({target: runningJobExecutions.jobExecutionId})\n .returning({claimedAt: runningJobExecutions.startedAt});\n\n const claimed = inserted[0];\n if (!claimed) return null;\n\n queueTimeObservation = {\n durationMilliseconds: claimed.claimedAt.getTime() - row.createdAt.getTime(),\n provider: null,\n launchKind: params.maxClaims === null ? 'manual' : 'unknown',\n };\n\n const runnerInstanceCondition = runnerInstanceId\n ? eq(providerRunners.id, runnerInstanceId)\n : provisionerId && providerRunnerId\n ? and(\n eq(providerRunners.provisionerId, provisionerId),\n eq(providerRunners.providerRunnerId, providerRunnerId),\n )\n : null;\n if (runnerInstanceCondition) {\n const [claimedRunner] = await tx\n .update(providerRunners)\n .set({\n firstClaimedAt: sql`coalesce(${providerRunners.firstClaimedAt}, ${claimed.claimedAt})`,\n updatedAt: sql`now()`,\n })\n .where(runnerInstanceCondition)\n .returning({\n firstClaimedAt: providerRunners.firstClaimedAt,\n isFirstClaim: sql<boolean>`${providerRunners.firstClaimedAt} = ${claimed.claimedAt}`,\n provider: providerRunners.providerKind,\n launchKind: providerRunners.launchKind,\n runnerInstanceId: providerRunners.id,\n sessionCreatedAtEpochMs: sql<number | null>`(\n select extract(epoch from ${runnerSessions.createdAt})::double precision * 1000\n from ${runnerSessions}\n where ${runnerSessions.id} = ${params.runnerSessionId}\n )`,\n });\n if (claimedRunner && queueTimeObservation) {\n queueTimeObservation.provider = claimedRunner.provider;\n queueTimeObservation.launchKind = claimedRunner.launchKind;\n }\n if (\n claimedRunner?.isFirstClaim &&\n claimedRunner.firstClaimedAt !== null &&\n claimedRunner.sessionCreatedAtEpochMs !== null &&\n claimedRunner.sessionCreatedAtEpochMs !== undefined\n )\n activationToFirstClaimObservation = {\n durationMilliseconds:\n claimedRunner.firstClaimedAt.getTime() - claimedRunner.sessionCreatedAtEpochMs,\n provider: claimedRunner.provider,\n launchKind: claimedRunner.launchKind,\n runnerInstanceId: claimedRunner.runnerInstanceId,\n };\n }\n\n if (params.maxClaims !== null) {\n await tx\n .update(runnerSessions)\n .set({claimsUsed: sql`${runnerSessions.claimsUsed} + 1`, updatedAt: sql`now()`})\n .where(eq(runnerSessions.id, params.runnerSessionId));\n }\n\n // The running-row insert is the runner claiming the job execution. Emit in the same tx; the\n // payload carries the row's own claim instant so a consumer records the true time,\n // not the outbox drain time.\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_CLAIMED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n claimedAt: claimed.claimedAt.toISOString(),\n },\n });\n\n return {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n };\n });\n if (queueTimeObservation) recordJobExecutionQueueTime(queueTimeObservation);\n if (activationToFirstClaimObservation)\n recordProviderRunnerActivationToFirstClaim(activationToFirstClaimObservation);\n return result;\n}\n\nasync function touchRunnerSessionLiveness(params: {\n workspaceId: string;\n runnerSessionId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(runnerSessions)\n .set({updatedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.id, params.runnerSessionId),\n eq(runnerSessions.workspaceId, params.workspaceId),\n sql`${runnerSessions.updatedAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n );\n}\n\n/**\n * Releases a job execution's lease when the orchestration workflow finalizes it: deletes the\n * running-job-execution row AND any lingering pending row for the same execution, in one tx.\n * When the deleted lease was the last one for a terminal provider runner, it also releases the\n * runner's reservation in the same runner-owned transaction. Terminal reports and workflow lease\n * finalization remain independently retryable; they do not share a cross-module scope lock.\n * Idempotent (0-row no-op), no token scope (the workflow is authoritative), and\n * emits no event: the workflow already owns the outcome. Sweeping the pending row\n * too closes the at-least-once window where an enqueue retry left an orphan that a\n * later claim would otherwise pick up for an already-finished job execution.\n */\nexport async function releaseJobExecution(params: {jobExecutionId: string}): Promise<void> {\n await db().transaction(async (tx) => {\n await lockJobExecution(tx, params.jobExecutionId);\n\n // Delete pending before running to match `claimPendingJobExecution`'s lock-acquisition\n // order (it locks the pending row first, then the running row). A concurrent\n // claim picking up an orphan pending row for this same job execution would otherwise\n // deadlock against the reverse order here.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n const deletedRunningRows = await tx\n .delete(runningJobExecutions)\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId))\n .returning({\n workspaceId: runningJobExecutions.workspaceId,\n provisionerId: runningJobExecutions.provisionerId,\n providerRunnerId: runningJobExecutions.providerRunnerId,\n });\n\n const deletedRunningRow = deletedRunningRows[0];\n if (deletedRunningRow?.provisionerId && deletedRunningRow.providerRunnerId) {\n await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: null,\n provisionerId: deletedRunningRow.provisionerId,\n providerRunnerIds: [deletedRunningRow.providerRunnerId],\n requireUnlinkedSession: false,\n // Lock and re-check the runner row locally so terminal reporting remains retryable\n // without a workflow/runner scope lock.\n requireTerminalState: false,\n });\n }\n });\n}\n\n/**\n * Reaps stale leases (bounded by `limit`), emitting one\n * `runners.job.lease_expired` event per reaped job execution.\n *\n * The cutoff is re-checked in the DELETE, not just the locking subquery, so a\n * heartbeat landing mid-call spares the live row. Each reaped execution also sweeps its\n * pending row: a failed best-effort `releaseJobExecution` would otherwise leave an orphan\n * that a later claim re-runs as an already-finished job execution.\n *\n * Locks pending-then-running to match `claimPendingJobExecution`, `releaseJobExecution`, and\n * `reconcileTerminalJobExecution`. The stale candidate scan intentionally does not lock running\n * rows first; the running-row DELETE re-checks the stale predicate after the pending-row sweep.\n */\nexport async function expireStuckJobExecutions(params: {\n thresholdSeconds: number;\n noFirstHeartbeatGraceSeconds: number;\n limit?: number;\n}): Promise<\n Array<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n }>\n> {\n const reaped = await db().transaction(async (tx) => {\n const heartbeatCutoff = sql`now() - (${params.thresholdSeconds} || ' seconds')::interval`;\n const firstHeartbeatCutoff = sql`now() - (${params.noFirstHeartbeatGraceSeconds} || ' seconds')::interval`;\n const stalePredicate = or(\n and(\n isNull(runningJobExecutions.firstHeartbeatAt),\n lte(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n lt(runningJobExecutions.startedAt, firstHeartbeatCutoff),\n ),\n and(\n or(\n isNotNull(runningJobExecutions.firstHeartbeatAt),\n gt(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n ),\n lt(runningJobExecutions.lastHeartbeatAt, heartbeatCutoff),\n ),\n );\n\n const staleRows = await tx\n .select({\n id: runningJobExecutions.id,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n })\n .from(runningJobExecutions)\n .where(\n and(\n stalePredicate,\n sql`\n pg_try_advisory_xact_lock(\n hashtext(${runnerJobExecutionLockPrefix} || ${runningJobExecutions.jobExecutionId}::text)\n )\n `,\n ),\n )\n .orderBy(\n asc(\n sql`CASE WHEN ${runningJobExecutions.firstHeartbeatAt} IS NULL AND ${runningJobExecutions.lastHeartbeatAt} <= ${runningJobExecutions.startedAt} THEN ${runningJobExecutions.startedAt} ELSE ${runningJobExecutions.lastHeartbeatAt} END`,\n ),\n asc(runningJobExecutions.id),\n )\n .limit(params.limit ?? 100);\n\n if (staleRows.length === 0) return [];\n\n const staleIds = staleRows.map((row) => row.id);\n const staleJobExecutionIds = staleRows.map((row) => row.jobExecutionId);\n\n // Sweep pending rows first so this transaction cannot hold a running-row lock while waiting\n // for a pending-row lock held by reconciliation or a claim of an orphan pending row. The\n // advisory lock acquired in the candidate scan also makes enqueue retries wait until this\n // transaction has either reaped the execution or released its lock without selecting it.\n await tx\n .delete(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.jobExecutionId, staleJobExecutionIds));\n\n const deleted = await tx\n .delete(runningJobExecutions)\n .where(and(inArray(runningJobExecutions.id, staleIds), stalePredicate))\n .returning({\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n });\n\n if (deleted.length === 0) return [];\n\n await writeOutboxEvents<RunnersEventMap>(\n tx,\n runnersOutbox,\n deleted.map((row) => ({\n type: RUNNER_JOB_LEASE_EXPIRED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n },\n })),\n );\n\n return deleted;\n });\n\n if (reaped.length > 0) jobExecutionLeaseExpiredCount.add(reaped.length);\n\n return reaped;\n}\n\nexport async function getJobExecutionQueueDepth(): Promise<{\n pendingJobExecutions: number;\n runningJobExecutions: number;\n}> {\n const [pending] = await db().select({value: count()}).from(pendingJobExecutions);\n const [running] = await db().select({value: count()}).from(runningJobExecutions);\n return {\n pendingJobExecutions: pending?.value ?? 0,\n runningJobExecutions: running?.value ?? 0,\n };\n}\n\nexport async function listActiveRunningJobExecutions(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<ActiveRunningJobExecution[]> {\n return await db()\n .select({\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n projectId: runningJobExecutions.projectId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n provisionerId: runningJobExecutions.provisionerId,\n providerRunnerId: runningJobExecutions.providerRunnerId,\n requiredLabels: runningJobExecutions.requiredLabels,\n runnerLabels: runningJobExecutions.runnerLabels,\n startedAt: runningJobExecutions.startedAt,\n lastHeartbeatAt: runningJobExecutions.lastHeartbeatAt,\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n sql`${runningJobExecutions.lastHeartbeatAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(runningJobExecutions.lastHeartbeatAt), desc(runningJobExecutions.id))\n .limit(params.limit ?? 1000);\n}\n\nexport async function listRunningJobExecutionsByRunnerInstanceTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n providerRunnerIds: string[];\n },\n): Promise<RunnerInstanceBoundJobExecution[]> {\n if (params.providerRunnerIds.length === 0) return [];\n\n const duplicateRows = await tx\n .select({\n providerRunnerId: runningJobExecutions.providerRunnerId,\n count: count(),\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n inArray(runningJobExecutions.providerRunnerId, params.providerRunnerIds),\n ),\n )\n .groupBy(runningJobExecutions.providerRunnerId)\n .having(sql`count(*) > 1`);\n\n const duplicateRunnerInstanceIds = duplicateRows.flatMap((row) =>\n row.providerRunnerId ? [row.providerRunnerId] : [],\n );\n if (duplicateRunnerInstanceIds.length > 0) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: duplicateRunnerInstanceIds,\n },\n 'multiple running job executions are bound to the same provisioned runner',\n );\n }\n\n const result = await tx.execute<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date | string;\n lastHeartbeatAt: Date | string;\n cancellationRequestedAt: Date | string | null;\n }>(sql`\n SELECT DISTINCT ON (${runningJobExecutions.providerRunnerId})\n ${runningJobExecutions.workflowRunId} AS \"workflowRunId\",\n ${runningJobExecutions.workflowRunAttemptId} AS \"workflowRunAttemptId\",\n ${runningJobExecutions.jobId} AS \"jobId\",\n ${runningJobExecutions.jobExecutionId} AS \"jobExecutionId\",\n ${runningJobExecutions.providerRunnerId} AS \"providerRunnerId\",\n ${runningJobExecutions.startedAt} AS \"startedAt\",\n ${runningJobExecutions.lastHeartbeatAt} AS \"lastHeartbeatAt\",\n ${runningJobExecutions.cancellationRequestedAt} AS \"cancellationRequestedAt\"\n FROM ${runningJobExecutions}\n WHERE\n ${runningJobExecutions.workspaceId} = ${params.workspaceId}\n AND ${runningJobExecutions.provisionerId} = ${params.provisionerId}\n AND ${runningJobExecutions.providerRunnerId} IN (${sql.join(\n params.providerRunnerIds.map((providerRunnerId) => sql`${providerRunnerId}`),\n sql`, `,\n )})\n ORDER BY ${runningJobExecutions.providerRunnerId}, ${runningJobExecutions.startedAt} DESC, ${runningJobExecutions.jobExecutionId} DESC\n `);\n\n return result.rows.map((row) => ({\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n providerRunnerId: row.providerRunnerId,\n startedAt: toDate(row.startedAt),\n lastHeartbeatAt: toDate(row.lastHeartbeatAt),\n cancellationRequestedAt: row.cancellationRequestedAt\n ? toDate(row.cancellationRequestedAt)\n : null,\n }));\n}\n\nfunction toDate(value: Date | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\nexport async function isJobLeaseActive(params: {\n jobId?: string;\n jobExecutionId: string;\n runnerSessionId: string;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n params.jobId === undefined ? undefined : eq(runningJobExecutions.jobId, params.jobId),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nexport async function recordHeartbeat(params: {\n jobExecutionId: string;\n runnerSessionId: string;\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<{\n cancellationRequested: boolean;\n previousToolCapabilities: RunnerToolCapabilitiesDto | null;\n currentToolCapabilities: RunnerToolCapabilitiesDto | null;\n runningJobExecution: {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n workspaceId: string;\n runnerSessionId: string;\n };\n}> {\n const result = await db().transaction(async (tx) => {\n const updated = await tx\n .update(runningJobExecutions)\n .set({\n firstHeartbeatAt: sql`COALESCE(${runningJobExecutions.firstHeartbeatAt}, now())`,\n lastHeartbeatAt: sql`now()`,\n })\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n ),\n )\n .returning({\n cancellationRequestedAt: runningJobExecutions.cancellationRequestedAt,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n projectId: runningJobExecutions.projectId,\n workspaceId: runningJobExecutions.workspaceId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n });\n\n const row = updated[0];\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n\n const [previous] = await tx\n .select({toolCapabilities: runnerSessions.toolCapabilities})\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n const [session] = await tx\n .update(runnerSessions)\n .set({\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n updatedAt: sql`now()`,\n })\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .returning({toolCapabilities: runnerSessions.toolCapabilities});\n\n return {\n row,\n previousToolCapabilities: previous?.toolCapabilities ?? null,\n currentToolCapabilities: session?.toolCapabilities ?? null,\n };\n });\n\n const row = result.row;\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n return {\n cancellationRequested: row.cancellationRequestedAt !== null,\n previousToolCapabilities: result.previousToolCapabilities,\n currentToolCapabilities: result.currentToolCapabilities,\n runningJobExecution: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n workspaceId: row.workspaceId,\n runnerSessionId: row.runnerSessionId,\n },\n };\n}\n\n/**\n * Reconciles a terminal job execution with runner state in one transaction: removes its pending\n * queue row and requests cancellation on its running lease, if either exists. The operation is\n * idempotent and preserves the first cancellation-request timestamp.\n */\nexport async function reconcileTerminalJobExecution(params: {\n jobExecutionId: string;\n}): Promise<void> {\n await db().transaction(async (tx) => {\n await lockJobExecution(tx, params.jobExecutionId);\n\n // Delete pending before updating running to match claim/release lock order. Claim locks\n // pending rows with SKIP LOCKED before inserting the running lease, so this ordering makes\n // a concurrent terminal reconciliation either win before claim or cancel the new lease.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\nexport async function cancelRunnerJobs(params: {jobIds: string[]}): Promise<void> {\n if (params.jobIds.length === 0) return;\n\n await db().transaction(async (tx) => {\n await tx.delete(pendingJobExecutions).where(inArray(pendingJobExecutions.jobId, params.jobIds));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(inArray(runningJobExecutions.jobId, params.jobIds));\n });\n}\n"],"names":["RUNNER_JOB_CLAIMED","RUNNER_JOB_LEASE_EXPIRED","RUNNER_JOB_QUEUED","logger","writeOutboxEvent","writeOutboxEvents","canonicalizeLabels","and","arrayContained","asc","count","desc","eq","gt","inArray","isNotNull","isNull","lt","lte","or","sql","EmptyRequiredLabelsError","RunnerSessionExhaustedError","RunningJobExecutionNotFoundError","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","recordJobExecutionQueueTime","recordProviderRunnerActivationToFirstClaim","db","releaseTerminalRunnerInstanceReservationsByIds","runnersOutbox","pendingJobExecutions","providerRunners","runnerSessions","runningJobExecutions","runnerJobExecutionLockPrefix","lockJobExecution","tx","jobExecutionId","execute","getWorkspaceJobCounts","params","pendingRows","runningRows","Promise","all","select","workspaceId","from","where","workspaceIds","groupBy","queuedByWorkspace","Map","map","row","Number","runningByWorkspace","queued","get","running","enqueueJobExecution","requiredLabels","length","enqueued","transaction","leaseExpired","id","eventType","payload","limit","inserted","insert","values","workflowRunId","workflowRunAttemptId","jobId","projectId","onConflictDoNothing","target","returning","createdAt","type","queuedAt","toISOString","add","claimPendingJobExecution","touchRunnerSessionLiveness","runnerSessionId","throttleSeconds","runnerSessionLivenessThrottleSeconds","sessionLabels","activationToFirstClaimObservation","queueTimeObservation","result","provisionerId","providerRunnerId","runnerInstanceId","maxClaims","session","claimsUsed","revokedAt","for","candidate","orderBy","skipLocked","as","delete","runnerLabels","claimedAt","startedAt","claimed","durationMilliseconds","getTime","provider","launchKind","runnerInstanceCondition","claimedRunner","update","set","firstClaimedAt","updatedAt","isFirstClaim","providerKind","sessionCreatedAtEpochMs","undefined","releaseJobExecution","deletedRunningRows","deletedRunningRow","providerRunnerIds","requireUnlinkedSession","requireTerminalState","expireStuckJobExecutions","reaped","heartbeatCutoff","thresholdSeconds","firstHeartbeatCutoff","noFirstHeartbeatGraceSeconds","stalePredicate","firstHeartbeatAt","lastHeartbeatAt","staleRows","staleIds","staleJobExecutionIds","deleted","getJobExecutionQueueDepth","pending","value","listActiveRunningJobExecutions","windowSeconds","listRunningJobExecutionsByRunnerInstanceTx","duplicateRows","having","duplicateRunnerInstanceIds","flatMap","warn","cancellationRequestedAt","join","rows","toDate","Date","isJobLeaseActive","recordHeartbeat","updated","previous","toolCapabilities","toolCapabilitiesReportedAt","previousToolCapabilities","currentToolCapabilities","cancellationRequested","runningJobExecution","reconcileTerminalJobExecution","cancelRunnerJobs","jobIds"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provisioner-tokens.d.ts","sourceRoot":"","sources":["../../src/db/provisioner-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EAE1B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAC,KAAK,iBAAiB,EAAyB,MAAM,uBAAuB,CAAC;AAGrF,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"provisioner-tokens.d.ts","sourceRoot":"","sources":["../../src/db/provisioner-tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,7 @@ import { writeOutboxEvent } from '@shipfox/node-outbox';
|
|
|
3
3
|
import { and, desc, eq, gt, inArray, isNotNull, isNull, lte, or, sql } from 'drizzle-orm';
|
|
4
4
|
import { ProvisionerAdminIdempotencyKeyReuseError } from '#core/errors.js';
|
|
5
5
|
import { db } from './db.js';
|
|
6
|
+
import { releaseTerminalRunnerInstanceReservationsByIds } from './reservations.js';
|
|
6
7
|
import { runnersAdminCommandResults } from './schema/admin-command-results.js';
|
|
7
8
|
import { runnersOutbox } from './schema/outbox.js';
|
|
8
9
|
import { provisionerTokens, toProvisionerToken } from './schema/provisioner-tokens.js';
|
|
@@ -23,11 +24,22 @@ async function cascadeProvisionerRevocation(tx, provisionerId) {
|
|
|
23
24
|
}).where(and(isNull(runnerActivationTokens.consumedAt), isNull(runnerActivationTokens.revokedAt), inArray(runnerActivationTokens.runnerInstanceId, tx.select({
|
|
24
25
|
id: providerRunners.id
|
|
25
26
|
}).from(providerRunners).where(eq(providerRunners.provisionerId, provisionerId)))));
|
|
26
|
-
await tx.update(providerRunners).set({
|
|
27
|
+
const terminatedRows = await tx.update(providerRunners).set({
|
|
27
28
|
state: 'terminated',
|
|
28
29
|
terminatedAt: sql`now()`,
|
|
29
30
|
updatedAt: sql`now()`
|
|
30
|
-
}).where(and(eq(providerRunners.provisionerId, provisionerId), isNull(providerRunners.runnerSessionId)))
|
|
31
|
+
}).where(and(eq(providerRunners.provisionerId, provisionerId), isNull(providerRunners.runnerSessionId))).returning({
|
|
32
|
+
id: providerRunners.id
|
|
33
|
+
});
|
|
34
|
+
const runnerInstanceIds = terminatedRows.map((row)=>row.id);
|
|
35
|
+
if (runnerInstanceIds.length > 0) {
|
|
36
|
+
await releaseTerminalRunnerInstanceReservationsByIds(tx, {
|
|
37
|
+
workspaceId: null,
|
|
38
|
+
provisionerId,
|
|
39
|
+
runnerInstanceIds,
|
|
40
|
+
requireUnlinkedSession: false
|
|
41
|
+
});
|
|
42
|
+
}
|
|
31
43
|
await tx.update(runnerSessions).set({
|
|
32
44
|
revokedAt: sql`now()`
|
|
33
45
|
}).where(and(eq(runnerSessions.provisionerId, provisionerId), eq(runnerSessions.claimsUsed, 0), isNull(runnerSessions.revokedAt)));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/provisioner-tokens.ts"],"sourcesContent":["import type {\n AdministrationActionEvent,\n AdministrationActionEventMap,\n} from '@shipfox/api-common-dto';\nimport {type TimestampIdCursor, timestampIdCursorWhere} from '@shipfox/node-drizzle';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {and, desc, eq, gt, inArray, isNotNull, isNull, lte, or, type SQL, sql} from 'drizzle-orm';\nimport type {\n ActiveProvisionerToken,\n ProvisionerScope,\n ProvisionerToken,\n} from '#core/entities/provisioner-token.js';\nimport {ProvisionerAdminIdempotencyKeyReuseError} from '#core/errors.js';\nimport {db} from './db.js';\nimport {runnersAdminCommandResults} from './schema/admin-command-results.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {provisionerTokens, toProvisionerToken} from './schema/provisioner-tokens.js';\nimport {runnerActivationTokens} from './schema/runner-activation-tokens.js';\nimport {runnerBootstrapTokens, runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\n\ntype Tx = Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0];\n\nexport interface CreateProvisionerTokenParams {\n scope: ProvisionerScope;\n workspaceId?: string | undefined;\n hashedToken: string;\n prefix: string;\n createdByUserId: string;\n name?: string | undefined;\n expiresAt?: Date | undefined;\n}\n\nasync function cascadeProvisionerRevocation(tx: Tx, provisionerId: string) {\n await tx\n .update(runnerBootstrapTokens)\n .set({revokedAt: sql`now()`})\n .where(eq(runnerBootstrapTokens.provisionerId, provisionerId));\n await tx\n .update(runnerControlSessions)\n .set({closedAt: sql`now()`, closeReason: 'provisioner-revoked'})\n .where(\n and(\n eq(runnerControlSessions.provisionerId, provisionerId),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n inArray(\n runnerActivationTokens.runnerInstanceId,\n tx\n .select({id: providerRunners.id})\n .from(providerRunners)\n .where(eq(providerRunners.provisionerId, provisionerId)),\n ),\n ),\n );\n await tx\n .update(providerRunners)\n .set({state: 'terminated', terminatedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.provisionerId, provisionerId),\n isNull(providerRunners.runnerSessionId),\n ),\n );\n await tx\n .update(runnerSessions)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.provisionerId, provisionerId),\n eq(runnerSessions.claimsUsed, 0),\n isNull(runnerSessions.revokedAt),\n ),\n );\n}\n\nasync function insertProvisionerToken(tx: Tx, params: CreateProvisionerTokenParams) {\n const rows = await tx\n .insert(provisionerTokens)\n .values({\n scope: params.scope,\n workspaceId: params.workspaceId ?? null,\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n createdByUserId: params.createdByUserId,\n name: params.name ?? null,\n expiresAt: params.expiresAt ?? null,\n })\n .returning();\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n return row;\n}\n\nexport async function createProvisionerToken(\n params: CreateProvisionerTokenParams,\n): Promise<ProvisionerToken> {\n const row = await db().transaction((tx) => insertProvisionerToken(tx, params));\n return toProvisionerToken(row);\n}\n\ninterface AuditedProvisionerTokenCommandParams {\n actorId: string;\n command: string;\n correlationId: string;\n idempotencyKeyFingerprint: string;\n requestFingerprint: string;\n event: (tokenId: string) => AdministrationActionEvent;\n}\n\nasync function lockAdminCommand(\n tx: Tx,\n params: Pick<AuditedProvisionerTokenCommandParams, 'actorId' | 'idempotencyKeyFingerprint'>,\n): Promise<void> {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`runners_admin_command:${params.actorId}:${params.idempotencyKeyFingerprint}`}))`,\n );\n}\n\nasync function loadAdminCommandResult(\n tx: Tx,\n params: Pick<\n AuditedProvisionerTokenCommandParams,\n 'actorId' | 'idempotencyKeyFingerprint' | 'requestFingerprint'\n > & {command: string},\n) {\n const rows = await tx\n .select()\n .from(runnersAdminCommandResults)\n .where(\n and(\n eq(runnersAdminCommandResults.actorId, params.actorId),\n eq(runnersAdminCommandResults.idempotencyKeyFingerprint, params.idempotencyKeyFingerprint),\n ),\n )\n .limit(1);\n const result = rows[0];\n if (!result) return undefined;\n if (\n result.command !== params.command ||\n result.requestFingerprint !== params.requestFingerprint\n ) {\n throw new ProvisionerAdminIdempotencyKeyReuseError();\n }\n return result;\n}\n\nasync function storeAdminCommandResult(\n tx: Tx,\n params: AuditedProvisionerTokenCommandParams,\n result: {provisionerTokenId: string; correlationId: string},\n): Promise<void> {\n await tx.insert(runnersAdminCommandResults).values({\n actorId: params.actorId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n command: params.command,\n requestFingerprint: params.requestFingerprint,\n result,\n });\n}\n\nasync function writeAdministrationAction(tx: Tx, event: AdministrationActionEvent): Promise<void> {\n await writeOutboxEvent<AdministrationActionEventMap>(tx, runnersOutbox, {\n type: 'administration.action.performed',\n payload: event,\n });\n}\n\nexport async function createInstallationProvisionerTokenWithAudit(\n params: AuditedProvisionerTokenCommandParams & {\n name?: string | undefined;\n ttlSeconds?: number | undefined;\n hashedToken: string;\n prefix: string;\n },\n): Promise<{token: ProvisionerToken; correlationId: string; replayed: boolean}> {\n const command = 'runners.provisioner_token.create';\n return await db().transaction(async (tx) => {\n await lockAdminCommand(tx, params);\n const existing = await loadAdminCommandResult(tx, {\n actorId: params.actorId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n requestFingerprint: params.requestFingerprint,\n command,\n });\n if (existing) {\n const rows = await tx\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.id, existing.result.provisionerTokenId))\n .limit(1);\n const row = rows[0];\n if (!row) throw new Error('Idempotent provisioner token result is missing');\n return {\n token: toProvisionerToken(row),\n correlationId: existing.result.correlationId,\n replayed: true,\n };\n }\n\n const expiresAt =\n params.ttlSeconds === undefined ? undefined : new Date(Date.now() + params.ttlSeconds * 1000);\n const row = await insertProvisionerToken(tx, {\n scope: 'installation',\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n createdByUserId: params.actorId,\n name: params.name,\n expiresAt,\n });\n const event = params.event(row.id);\n await writeAdministrationAction(tx, event);\n await storeAdminCommandResult(tx, params, {\n provisionerTokenId: row.id,\n correlationId: event.correlationId,\n });\n return {token: toProvisionerToken(row), correlationId: event.correlationId, replayed: false};\n });\n}\n\nexport async function revokeInstallationProvisionerToken(params: {\n tokenId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db().transaction(async (tx) => {\n const rows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n if (rows[0]) {\n await cascadeProvisionerRevocation(tx, params.tokenId);\n }\n return rows;\n });\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.scope, 'installation')),\n )\n .limit(1);\n const existingRow = existingRows[0];\n return existingRow ? toProvisionerToken(existingRow) : undefined;\n}\n\nexport async function revokeInstallationProvisionerTokenWithAudit(\n params: AuditedProvisionerTokenCommandParams & {tokenId: string},\n): Promise<{token: ProvisionerToken; correlationId: string; replayed: boolean} | undefined> {\n const command = 'runners.provisioner_token.revoke';\n return await db().transaction(async (tx) => {\n await lockAdminCommand(tx, params);\n const existing = await loadAdminCommandResult(tx, {\n actorId: params.actorId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n requestFingerprint: params.requestFingerprint,\n command,\n });\n if (existing) {\n const rows = await tx\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.id, existing.result.provisionerTokenId))\n .limit(1);\n const row = rows[0];\n if (!row) throw new Error('Idempotent provisioner token result is missing');\n return {\n token: toProvisionerToken(row),\n correlationId: existing.result.correlationId,\n replayed: true,\n };\n }\n\n const updatedRows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.actorId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n const row = updatedRows[0];\n if (row) await cascadeProvisionerRevocation(tx, params.tokenId);\n\n const existingRows = row\n ? [row]\n : await tx\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n ),\n )\n .limit(1);\n const tokenRow = existingRows[0];\n if (!tokenRow) return undefined;\n\n const changed = row !== undefined;\n const event = changed ? params.event(tokenRow.id) : undefined;\n if (event) await writeAdministrationAction(tx, event);\n await storeAdminCommandResult(tx, params, {\n provisionerTokenId: tokenRow.id,\n correlationId: event?.correlationId ?? params.correlationId,\n });\n return {\n token: toProvisionerToken(tokenRow),\n correlationId: event?.correlationId ?? params.correlationId,\n replayed: false,\n };\n });\n}\n\nexport type InstallationProvisionerTokenStatus = 'active' | 'expired' | 'revoked';\n\nexport interface ListInstallationProvisionerTokensParams {\n limit: number;\n cursor?: TimestampIdCursor | undefined;\n status?: InstallationProvisionerTokenStatus | undefined;\n}\n\nexport async function listInstallationProvisionerTokens(\n params: ListInstallationProvisionerTokensParams,\n): Promise<{tokens: ProvisionerToken[]; nextCursor: TimestampIdCursor | null}> {\n const conditions: SQL[] = [eq(provisionerTokens.scope, 'installation')];\n const cursor = timestampIdCursorWhere({\n timestampColumn: provisionerTokens.createdAt,\n idColumn: provisionerTokens.id,\n cursor: params.cursor,\n });\n if (cursor) conditions.push(cursor);\n\n if (params.status === 'active') {\n conditions.push(isNull(provisionerTokens.revokedAt));\n const activeExpiry = or(\n isNull(provisionerTokens.expiresAt),\n gt(provisionerTokens.expiresAt, sql`now()`),\n );\n if (activeExpiry) conditions.push(activeExpiry);\n }\n if (params.status === 'expired') {\n conditions.push(\n isNull(provisionerTokens.revokedAt),\n isNotNull(provisionerTokens.expiresAt),\n lte(provisionerTokens.expiresAt, sql`now()`),\n );\n }\n if (params.status === 'revoked') conditions.push(isNotNull(provisionerTokens.revokedAt));\n\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(and(...conditions))\n .orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id))\n .limit(params.limit + 1);\n const pageRows = rows.length > params.limit ? rows.slice(0, params.limit) : rows;\n const last = pageRows.at(-1);\n return {\n tokens: pageRows.map(toProvisionerToken),\n nextCursor:\n rows.length > params.limit && last ? {createdAt: last.createdAt, id: last.id} : null,\n };\n}\n\nexport async function listUsableProvisionerTokensByWorkspaceId(\n workspaceId: string,\n): Promise<ProvisionerToken[]> {\n const now = new Date();\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, now)),\n ),\n )\n .orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken);\n}\n\nexport async function resolveProvisionerTokenByHash(\n hashedToken: string,\n): Promise<ProvisionerToken | undefined> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.hashedToken, hashedToken))\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProvisionerToken(row);\n}\n\nexport async function revokeProvisionerToken(params: {\n tokenId: string;\n workspaceId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db().transaction(async (tx) => {\n const rows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n if (rows[0]) await cascadeProvisionerRevocation(tx, params.tokenId);\n return rows;\n });\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n ),\n )\n .limit(1);\n\n const existingRow = existingRows[0];\n if (!existingRow) return undefined;\n return toProvisionerToken(existingRow);\n}\n\nexport async function touchProvisionerLastSeen(params: {\n tokenId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(provisionerTokens)\n .set({lastSeenAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n or(\n isNull(provisionerTokens.lastSeenAt),\n sql`${provisionerTokens.lastSeenAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n ),\n );\n}\n\nexport async function listActiveProvisionerTokens(params: {\n workspaceId: string;\n windowSeconds: number;\n}): Promise<ActiveProvisionerToken[]> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)),\n sql`${provisionerTokens.lastSeenAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(provisionerTokens.lastSeenAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken).filter((token): token is ActiveProvisionerToken => {\n return token.lastSeenAt !== null;\n });\n}\n"],"names":["timestampIdCursorWhere","writeOutboxEvent","and","desc","eq","gt","inArray","isNotNull","isNull","lte","or","sql","ProvisionerAdminIdempotencyKeyReuseError","db","runnersAdminCommandResults","runnersOutbox","provisionerTokens","toProvisionerToken","runnerActivationTokens","runnerBootstrapTokens","runnerControlSessions","providerRunners","runnerSessions","cascadeProvisionerRevocation","tx","provisionerId","update","set","revokedAt","where","closedAt","closeReason","consumedAt","runnerInstanceId","select","id","from","state","terminatedAt","updatedAt","runnerSessionId","claimsUsed","insertProvisionerToken","params","rows","insert","values","scope","workspaceId","hashedToken","prefix","createdByUserId","name","expiresAt","returning","row","Error","createProvisionerToken","transaction","lockAdminCommand","execute","actorId","idempotencyKeyFingerprint","loadAdminCommandResult","limit","result","undefined","command","requestFingerprint","storeAdminCommandResult","writeAdministrationAction","event","type","payload","createInstallationProvisionerTokenWithAudit","existing","provisionerTokenId","token","correlationId","replayed","ttlSeconds","Date","now","revokeInstallationProvisionerToken","revokedByUserId","tokenId","existingRows","existingRow","revokeInstallationProvisionerTokenWithAudit","updatedRows","tokenRow","changed","listInstallationProvisionerTokens","conditions","cursor","timestampColumn","createdAt","idColumn","push","status","activeExpiry","orderBy","pageRows","length","slice","last","at","tokens","map","nextCursor","listUsableProvisionerTokensByWorkspaceId","resolveProvisionerTokenByHash","revokeProvisionerToken","touchProvisionerLastSeen","lastSeenAt","throttleSeconds","listActiveProvisionerTokens","windowSeconds","filter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/provisioner-tokens.ts"],"sourcesContent":["import type {\n AdministrationActionEvent,\n AdministrationActionEventMap,\n} from '@shipfox/api-common-dto';\nimport {type TimestampIdCursor, timestampIdCursorWhere} from '@shipfox/node-drizzle';\nimport {writeOutboxEvent} from '@shipfox/node-outbox';\nimport {and, desc, eq, gt, inArray, isNotNull, isNull, lte, or, type SQL, sql} from 'drizzle-orm';\nimport type {\n ActiveProvisionerToken,\n ProvisionerScope,\n ProvisionerToken,\n} from '#core/entities/provisioner-token.js';\nimport {ProvisionerAdminIdempotencyKeyReuseError} from '#core/errors.js';\nimport {db} from './db.js';\nimport {releaseTerminalRunnerInstanceReservationsByIds} from './reservations.js';\nimport {runnersAdminCommandResults} from './schema/admin-command-results.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {provisionerTokens, toProvisionerToken} from './schema/provisioner-tokens.js';\nimport {runnerActivationTokens} from './schema/runner-activation-tokens.js';\nimport {runnerBootstrapTokens, runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\n\ntype Tx = Parameters<Parameters<ReturnType<typeof db>['transaction']>[0]>[0];\n\nexport interface CreateProvisionerTokenParams {\n scope: ProvisionerScope;\n workspaceId?: string | undefined;\n hashedToken: string;\n prefix: string;\n createdByUserId: string;\n name?: string | undefined;\n expiresAt?: Date | undefined;\n}\n\nasync function cascadeProvisionerRevocation(tx: Tx, provisionerId: string) {\n await tx\n .update(runnerBootstrapTokens)\n .set({revokedAt: sql`now()`})\n .where(eq(runnerBootstrapTokens.provisionerId, provisionerId));\n await tx\n .update(runnerControlSessions)\n .set({closedAt: sql`now()`, closeReason: 'provisioner-revoked'})\n .where(\n and(\n eq(runnerControlSessions.provisionerId, provisionerId),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n inArray(\n runnerActivationTokens.runnerInstanceId,\n tx\n .select({id: providerRunners.id})\n .from(providerRunners)\n .where(eq(providerRunners.provisionerId, provisionerId)),\n ),\n ),\n );\n const terminatedRows = await tx\n .update(providerRunners)\n .set({state: 'terminated', terminatedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.provisionerId, provisionerId),\n isNull(providerRunners.runnerSessionId),\n ),\n )\n .returning({id: providerRunners.id});\n const runnerInstanceIds = terminatedRows.map((row) => row.id);\n if (runnerInstanceIds.length > 0) {\n await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: null,\n provisionerId,\n runnerInstanceIds,\n requireUnlinkedSession: false,\n });\n }\n await tx\n .update(runnerSessions)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.provisionerId, provisionerId),\n eq(runnerSessions.claimsUsed, 0),\n isNull(runnerSessions.revokedAt),\n ),\n );\n}\n\nasync function insertProvisionerToken(tx: Tx, params: CreateProvisionerTokenParams) {\n const rows = await tx\n .insert(provisionerTokens)\n .values({\n scope: params.scope,\n workspaceId: params.workspaceId ?? null,\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n createdByUserId: params.createdByUserId,\n name: params.name ?? null,\n expiresAt: params.expiresAt ?? null,\n })\n .returning();\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n return row;\n}\n\nexport async function createProvisionerToken(\n params: CreateProvisionerTokenParams,\n): Promise<ProvisionerToken> {\n const row = await db().transaction((tx) => insertProvisionerToken(tx, params));\n return toProvisionerToken(row);\n}\n\ninterface AuditedProvisionerTokenCommandParams {\n actorId: string;\n command: string;\n correlationId: string;\n idempotencyKeyFingerprint: string;\n requestFingerprint: string;\n event: (tokenId: string) => AdministrationActionEvent;\n}\n\nasync function lockAdminCommand(\n tx: Tx,\n params: Pick<AuditedProvisionerTokenCommandParams, 'actorId' | 'idempotencyKeyFingerprint'>,\n): Promise<void> {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`runners_admin_command:${params.actorId}:${params.idempotencyKeyFingerprint}`}))`,\n );\n}\n\nasync function loadAdminCommandResult(\n tx: Tx,\n params: Pick<\n AuditedProvisionerTokenCommandParams,\n 'actorId' | 'idempotencyKeyFingerprint' | 'requestFingerprint'\n > & {command: string},\n) {\n const rows = await tx\n .select()\n .from(runnersAdminCommandResults)\n .where(\n and(\n eq(runnersAdminCommandResults.actorId, params.actorId),\n eq(runnersAdminCommandResults.idempotencyKeyFingerprint, params.idempotencyKeyFingerprint),\n ),\n )\n .limit(1);\n const result = rows[0];\n if (!result) return undefined;\n if (\n result.command !== params.command ||\n result.requestFingerprint !== params.requestFingerprint\n ) {\n throw new ProvisionerAdminIdempotencyKeyReuseError();\n }\n return result;\n}\n\nasync function storeAdminCommandResult(\n tx: Tx,\n params: AuditedProvisionerTokenCommandParams,\n result: {provisionerTokenId: string; correlationId: string},\n): Promise<void> {\n await tx.insert(runnersAdminCommandResults).values({\n actorId: params.actorId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n command: params.command,\n requestFingerprint: params.requestFingerprint,\n result,\n });\n}\n\nasync function writeAdministrationAction(tx: Tx, event: AdministrationActionEvent): Promise<void> {\n await writeOutboxEvent<AdministrationActionEventMap>(tx, runnersOutbox, {\n type: 'administration.action.performed',\n payload: event,\n });\n}\n\nexport async function createInstallationProvisionerTokenWithAudit(\n params: AuditedProvisionerTokenCommandParams & {\n name?: string | undefined;\n ttlSeconds?: number | undefined;\n hashedToken: string;\n prefix: string;\n },\n): Promise<{token: ProvisionerToken; correlationId: string; replayed: boolean}> {\n const command = 'runners.provisioner_token.create';\n return await db().transaction(async (tx) => {\n await lockAdminCommand(tx, params);\n const existing = await loadAdminCommandResult(tx, {\n actorId: params.actorId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n requestFingerprint: params.requestFingerprint,\n command,\n });\n if (existing) {\n const rows = await tx\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.id, existing.result.provisionerTokenId))\n .limit(1);\n const row = rows[0];\n if (!row) throw new Error('Idempotent provisioner token result is missing');\n return {\n token: toProvisionerToken(row),\n correlationId: existing.result.correlationId,\n replayed: true,\n };\n }\n\n const expiresAt =\n params.ttlSeconds === undefined ? undefined : new Date(Date.now() + params.ttlSeconds * 1000);\n const row = await insertProvisionerToken(tx, {\n scope: 'installation',\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n createdByUserId: params.actorId,\n name: params.name,\n expiresAt,\n });\n const event = params.event(row.id);\n await writeAdministrationAction(tx, event);\n await storeAdminCommandResult(tx, params, {\n provisionerTokenId: row.id,\n correlationId: event.correlationId,\n });\n return {token: toProvisionerToken(row), correlationId: event.correlationId, replayed: false};\n });\n}\n\nexport async function revokeInstallationProvisionerToken(params: {\n tokenId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db().transaction(async (tx) => {\n const rows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n if (rows[0]) {\n await cascadeProvisionerRevocation(tx, params.tokenId);\n }\n return rows;\n });\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(eq(provisionerTokens.id, params.tokenId), eq(provisionerTokens.scope, 'installation')),\n )\n .limit(1);\n const existingRow = existingRows[0];\n return existingRow ? toProvisionerToken(existingRow) : undefined;\n}\n\nexport async function revokeInstallationProvisionerTokenWithAudit(\n params: AuditedProvisionerTokenCommandParams & {tokenId: string},\n): Promise<{token: ProvisionerToken; correlationId: string; replayed: boolean} | undefined> {\n const command = 'runners.provisioner_token.revoke';\n return await db().transaction(async (tx) => {\n await lockAdminCommand(tx, params);\n const existing = await loadAdminCommandResult(tx, {\n actorId: params.actorId,\n idempotencyKeyFingerprint: params.idempotencyKeyFingerprint,\n requestFingerprint: params.requestFingerprint,\n command,\n });\n if (existing) {\n const rows = await tx\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.id, existing.result.provisionerTokenId))\n .limit(1);\n const row = rows[0];\n if (!row) throw new Error('Idempotent provisioner token result is missing');\n return {\n token: toProvisionerToken(row),\n correlationId: existing.result.correlationId,\n replayed: true,\n };\n }\n\n const updatedRows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.actorId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n const row = updatedRows[0];\n if (row) await cascadeProvisionerRevocation(tx, params.tokenId);\n\n const existingRows = row\n ? [row]\n : await tx\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.scope, 'installation'),\n ),\n )\n .limit(1);\n const tokenRow = existingRows[0];\n if (!tokenRow) return undefined;\n\n const changed = row !== undefined;\n const event = changed ? params.event(tokenRow.id) : undefined;\n if (event) await writeAdministrationAction(tx, event);\n await storeAdminCommandResult(tx, params, {\n provisionerTokenId: tokenRow.id,\n correlationId: event?.correlationId ?? params.correlationId,\n });\n return {\n token: toProvisionerToken(tokenRow),\n correlationId: event?.correlationId ?? params.correlationId,\n replayed: false,\n };\n });\n}\n\nexport type InstallationProvisionerTokenStatus = 'active' | 'expired' | 'revoked';\n\nexport interface ListInstallationProvisionerTokensParams {\n limit: number;\n cursor?: TimestampIdCursor | undefined;\n status?: InstallationProvisionerTokenStatus | undefined;\n}\n\nexport async function listInstallationProvisionerTokens(\n params: ListInstallationProvisionerTokensParams,\n): Promise<{tokens: ProvisionerToken[]; nextCursor: TimestampIdCursor | null}> {\n const conditions: SQL[] = [eq(provisionerTokens.scope, 'installation')];\n const cursor = timestampIdCursorWhere({\n timestampColumn: provisionerTokens.createdAt,\n idColumn: provisionerTokens.id,\n cursor: params.cursor,\n });\n if (cursor) conditions.push(cursor);\n\n if (params.status === 'active') {\n conditions.push(isNull(provisionerTokens.revokedAt));\n const activeExpiry = or(\n isNull(provisionerTokens.expiresAt),\n gt(provisionerTokens.expiresAt, sql`now()`),\n );\n if (activeExpiry) conditions.push(activeExpiry);\n }\n if (params.status === 'expired') {\n conditions.push(\n isNull(provisionerTokens.revokedAt),\n isNotNull(provisionerTokens.expiresAt),\n lte(provisionerTokens.expiresAt, sql`now()`),\n );\n }\n if (params.status === 'revoked') conditions.push(isNotNull(provisionerTokens.revokedAt));\n\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(and(...conditions))\n .orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id))\n .limit(params.limit + 1);\n const pageRows = rows.length > params.limit ? rows.slice(0, params.limit) : rows;\n const last = pageRows.at(-1);\n return {\n tokens: pageRows.map(toProvisionerToken),\n nextCursor:\n rows.length > params.limit && last ? {createdAt: last.createdAt, id: last.id} : null,\n };\n}\n\nexport async function listUsableProvisionerTokensByWorkspaceId(\n workspaceId: string,\n): Promise<ProvisionerToken[]> {\n const now = new Date();\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, now)),\n ),\n )\n .orderBy(desc(provisionerTokens.createdAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken);\n}\n\nexport async function resolveProvisionerTokenByHash(\n hashedToken: string,\n): Promise<ProvisionerToken | undefined> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(eq(provisionerTokens.hashedToken, hashedToken))\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toProvisionerToken(row);\n}\n\nexport async function revokeProvisionerToken(params: {\n tokenId: string;\n workspaceId: string;\n revokedByUserId: string;\n}): Promise<ProvisionerToken | undefined> {\n const rows = await db().transaction(async (tx) => {\n const rows = await tx\n .update(provisionerTokens)\n .set({revokedAt: new Date(), revokedByUserId: params.revokedByUserId, updatedAt: new Date()})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n ),\n )\n .returning();\n if (rows[0]) await cascadeProvisionerRevocation(tx, params.tokenId);\n return rows;\n });\n\n const row = rows[0];\n if (row) return toProvisionerToken(row);\n\n const existingRows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n ),\n )\n .limit(1);\n\n const existingRow = existingRows[0];\n if (!existingRow) return undefined;\n return toProvisionerToken(existingRow);\n}\n\nexport async function touchProvisionerLastSeen(params: {\n tokenId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(provisionerTokens)\n .set({lastSeenAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(provisionerTokens.id, params.tokenId),\n or(\n isNull(provisionerTokens.lastSeenAt),\n sql`${provisionerTokens.lastSeenAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n ),\n );\n}\n\nexport async function listActiveProvisionerTokens(params: {\n workspaceId: string;\n windowSeconds: number;\n}): Promise<ActiveProvisionerToken[]> {\n const rows = await db()\n .select()\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n isNull(provisionerTokens.revokedAt),\n or(isNull(provisionerTokens.expiresAt), gt(provisionerTokens.expiresAt, sql`now()`)),\n sql`${provisionerTokens.lastSeenAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(provisionerTokens.lastSeenAt), desc(provisionerTokens.id));\n\n return rows.map(toProvisionerToken).filter((token): token is ActiveProvisionerToken => {\n return token.lastSeenAt !== null;\n });\n}\n"],"names":["timestampIdCursorWhere","writeOutboxEvent","and","desc","eq","gt","inArray","isNotNull","isNull","lte","or","sql","ProvisionerAdminIdempotencyKeyReuseError","db","releaseTerminalRunnerInstanceReservationsByIds","runnersAdminCommandResults","runnersOutbox","provisionerTokens","toProvisionerToken","runnerActivationTokens","runnerBootstrapTokens","runnerControlSessions","providerRunners","runnerSessions","cascadeProvisionerRevocation","tx","provisionerId","update","set","revokedAt","where","closedAt","closeReason","consumedAt","runnerInstanceId","select","id","from","terminatedRows","state","terminatedAt","updatedAt","runnerSessionId","returning","runnerInstanceIds","map","row","length","workspaceId","requireUnlinkedSession","claimsUsed","insertProvisionerToken","params","rows","insert","values","scope","hashedToken","prefix","createdByUserId","name","expiresAt","Error","createProvisionerToken","transaction","lockAdminCommand","execute","actorId","idempotencyKeyFingerprint","loadAdminCommandResult","limit","result","undefined","command","requestFingerprint","storeAdminCommandResult","writeAdministrationAction","event","type","payload","createInstallationProvisionerTokenWithAudit","existing","provisionerTokenId","token","correlationId","replayed","ttlSeconds","Date","now","revokeInstallationProvisionerToken","revokedByUserId","tokenId","existingRows","existingRow","revokeInstallationProvisionerTokenWithAudit","updatedRows","tokenRow","changed","listInstallationProvisionerTokens","conditions","cursor","timestampColumn","createdAt","idColumn","push","status","activeExpiry","orderBy","pageRows","slice","last","at","tokens","nextCursor","listUsableProvisionerTokensByWorkspaceId","resolveProvisionerTokenByHash","revokeProvisionerToken","touchProvisionerLastSeen","lastSeenAt","throttleSeconds","listActiveProvisionerTokens","windowSeconds","filter"],"mappings":"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"}
|
|
@@ -76,5 +76,15 @@ export declare function releaseReservationUnits(tx: Tx, params: {
|
|
|
76
76
|
count: number;
|
|
77
77
|
}>;
|
|
78
78
|
}): Promise<number>;
|
|
79
|
+
export declare function releaseTerminalRunnerInstanceReservationsByIds(tx: Tx, params: {
|
|
80
|
+
workspaceId: string | null;
|
|
81
|
+
provisionerId: string;
|
|
82
|
+
providerRunnerIds?: string[];
|
|
83
|
+
runnerInstanceIds?: string[];
|
|
84
|
+
reportedAtByProviderRunnerId?: ReadonlyMap<string, Date>;
|
|
85
|
+
requireUnlinkedSession?: boolean;
|
|
86
|
+
/** Lock linked runners before rechecking terminal state for lease finalization. */
|
|
87
|
+
requireTerminalState?: boolean;
|
|
88
|
+
}): Promise<number>;
|
|
79
89
|
export {};
|
|
80
90
|
//# sourceMappingURL=reservations.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reservations.d.ts","sourceRoot":"","sources":["../../src/db/reservations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reservations.d.ts","sourceRoot":"","sources":["../../src/db/reservations.ts"],"names":[],"mappings":"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"}
|