@shipfox/api-runners 12.3.0 → 12.4.1
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 +36 -0
- package/dist/config.d.ts +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -2
- package/dist/config.js.map +1 -1
- package/dist/core/demand.d.ts +4 -2
- package/dist/core/demand.d.ts.map +1 -1
- package/dist/core/demand.js +22 -6
- package/dist/core/demand.js.map +1 -1
- package/dist/core/entities/reservation.d.ts +1 -0
- package/dist/core/entities/reservation.d.ts.map +1 -1
- package/dist/core/entities/reservation.js.map +1 -1
- package/dist/core/entities/runner-instance.d.ts +3 -0
- package/dist/core/entities/runner-instance.d.ts.map +1 -1
- package/dist/core/entities/runner-instance.js.map +1 -1
- package/dist/core/errors.d.ts +5 -1
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +9 -2
- package/dist/core/errors.js.map +1 -1
- package/dist/core/runner-activation.d.ts +4 -1
- package/dist/core/runner-activation.d.ts.map +1 -1
- package/dist/core/runner-activation.js +32 -3
- package/dist/core/runner-activation.js.map +1 -1
- package/dist/core/runner-control-sessions.d.ts +8 -4
- package/dist/core/runner-control-sessions.d.ts.map +1 -1
- package/dist/core/runner-control-sessions.js +116 -20
- package/dist/core/runner-control-sessions.js.map +1 -1
- package/dist/core/runner-instances.d.ts +1 -0
- package/dist/core/runner-instances.d.ts.map +1 -1
- package/dist/core/runner-instances.js +1 -0
- package/dist/core/runner-instances.js.map +1 -1
- package/dist/db/db.d.ts +68 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
- package/dist/db/ephemeral-registration-tokens.js +1 -1
- package/dist/db/ephemeral-registration-tokens.js.map +1 -1
- package/dist/db/job-executions.d.ts.map +1 -1
- package/dist/db/job-executions.js +35 -4
- package/dist/db/job-executions.js.map +1 -1
- package/dist/db/reservation-locks.d.ts +6 -0
- package/dist/db/reservation-locks.d.ts.map +1 -0
- package/dist/db/reservation-locks.js +15 -0
- package/dist/db/reservation-locks.js.map +1 -0
- package/dist/db/reservations.d.ts +17 -3
- package/dist/db/reservations.d.ts.map +1 -1
- package/dist/db/reservations.js +246 -51
- package/dist/db/reservations.js.map +1 -1
- package/dist/db/runner-assignments.d.ts +25 -1
- package/dist/db/runner-assignments.d.ts.map +1 -1
- package/dist/db/runner-assignments.js +160 -18
- package/dist/db/runner-assignments.js.map +1 -1
- package/dist/db/runner-instances.d.ts +11 -2
- package/dist/db/runner-instances.d.ts.map +1 -1
- package/dist/db/runner-instances.js +167 -24
- package/dist/db/runner-instances.js.map +1 -1
- package/dist/db/runner-sessions.d.ts.map +1 -1
- package/dist/db/runner-sessions.js +14 -1
- package/dist/db/runner-sessions.js.map +1 -1
- package/dist/db/runner-states.d.ts +2 -0
- package/dist/db/runner-states.d.ts.map +1 -0
- package/dist/db/runner-states.js +7 -0
- package/dist/db/runner-states.js.map +1 -0
- package/dist/db/schema/reservations.d.ts +18 -0
- package/dist/db/schema/reservations.d.ts.map +1 -1
- package/dist/db/schema/reservations.js +7 -1
- package/dist/db/schema/reservations.js.map +1 -1
- package/dist/db/schema/runner-instances.d.ts +18 -0
- package/dist/db/schema/runner-instances.d.ts.map +1 -1
- package/dist/db/schema/runner-instances.js +8 -0
- package/dist/db/schema/runner-instances.js.map +1 -1
- package/dist/metrics/index.d.ts +2 -2
- package/dist/metrics/index.d.ts.map +1 -1
- package/dist/metrics/index.js +1 -1
- package/dist/metrics/index.js.map +1 -1
- package/dist/metrics/instance.d.ts +72 -2
- package/dist/metrics/instance.d.ts.map +1 -1
- package/dist/metrics/instance.js +161 -1
- package/dist/metrics/instance.js.map +1 -1
- package/dist/metrics/service.d.ts.map +1 -1
- package/dist/metrics/service.js +25 -4
- package/dist/metrics/service.js.map +1 -1
- package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
- package/dist/presentation/dto/poll-demand.js +3 -0
- package/dist/presentation/dto/poll-demand.js.map +1 -1
- package/dist/presentation/dto/runner-instances.d.ts +4 -1
- package/dist/presentation/dto/runner-instances.d.ts.map +1 -1
- package/dist/presentation/dto/runner-instances.js +4 -1
- package/dist/presentation/dto/runner-instances.js.map +1 -1
- package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -1
- package/dist/presentation/routes/assign-runner-instances.js +10 -4
- package/dist/presentation/routes/assign-runner-instances.js.map +1 -1
- package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
- package/dist/presentation/routes/poll-demand.js +1 -0
- package/dist/presentation/routes/poll-demand.js.map +1 -1
- package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -1
- package/dist/presentation/routes/reconcile-runner-instances.js +4 -2
- package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -1
- package/dist/presentation/routes/runner-enrollment.d.ts +4 -1
- package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
- package/dist/presentation/routes/runner-enrollment.js +11 -6
- package/dist/presentation/routes/runner-enrollment.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0005_previous_lenny_balinger.sql +5 -0
- package/drizzle/meta/0005_snapshot.json +2220 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +6 -6
- package/src/config.test.ts +22 -0
- package/src/config.ts +15 -2
- package/src/core/demand.test.ts +192 -3
- package/src/core/demand.ts +44 -4
- package/src/core/entities/reservation.ts +1 -0
- package/src/core/entities/runner-instance.ts +4 -0
- package/src/core/errors.ts +30 -1
- package/src/core/runner-activation.ts +48 -2
- package/src/core/runner-control-sessions.test.ts +135 -3
- package/src/core/runner-control-sessions.ts +141 -19
- package/src/core/runner-instances.test.ts +19 -0
- package/src/core/runner-instances.ts +2 -0
- package/src/core/runner-sessions.test.ts +121 -1
- package/src/db/ephemeral-registration-tokens.test.ts +20 -1
- package/src/db/ephemeral-registration-tokens.ts +1 -0
- package/src/db/job-executions.test.ts +98 -12
- package/src/db/job-executions.ts +52 -4
- package/src/db/reservation-locks.ts +22 -0
- package/src/db/reservations.test.ts +733 -22
- package/src/db/reservations.ts +408 -144
- package/src/db/runner-assignments.test.ts +105 -1
- package/src/db/runner-assignments.ts +245 -25
- package/src/db/runner-instances.test.ts +357 -2
- package/src/db/runner-instances.ts +289 -55
- package/src/db/runner-sessions.ts +19 -1
- package/src/db/runner-states.ts +7 -0
- package/src/db/schema/reservations.ts +5 -1
- package/src/db/schema/runner-instances.ts +9 -0
- package/src/metrics/index.ts +24 -1
- package/src/metrics/instance.test.ts +118 -0
- package/src/metrics/instance.ts +247 -3
- package/src/metrics/service.test.ts +46 -1
- package/src/metrics/service.ts +55 -8
- package/src/presentation/dto/poll-demand.ts +3 -0
- package/src/presentation/dto/runner-instances.ts +8 -1
- package/src/presentation/routes/assign-runner-instances.ts +14 -2
- package/src/presentation/routes/late-runner-enrollment.test.ts +219 -2
- package/src/presentation/routes/poll-demand.test.ts +56 -0
- package/src/presentation/routes/poll-demand.ts +1 -0
- package/src/presentation/routes/reconcile-runner-instances.test.ts +34 -2
- package/src/presentation/routes/reconcile-runner-instances.ts +7 -1
- package/src/presentation/routes/runner-enrollment.test.ts +316 -3
- package/src/presentation/routes/runner-enrollment.ts +8 -5
- package/test/factories/reservation.ts +2 -0
- package/test/factories/runner-instance.ts +6 -0
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/core/runner-instances.ts"],"sourcesContent":["import type {RunnerInstance, RunnerInstanceState} from '#core/entities/runner-instance.js';\nimport {\n attachRunnerInstanceProviderId as attachRunnerInstanceProviderIdDb,\n isTerminalState,\n listActiveRunnerInstances,\n listActiveRunningJobExecutions,\n type RunnerInstanceReportEvent,\n reconcileRunnerInstances as reconcileRunnerInstancesDb,\n reportRunnerInstances as reportRunnerInstancesDb,\n} from '#db/index.js';\nimport type {\n ActiveRunningJobExecution,\n RunnerInstanceBoundJobExecution,\n} from '#db/job-executions.js';\nimport {\n providerRunnerAbsentTerminatedCount,\n providerRunnerReconcileCallCount,\n providerRunnerReportCount,\n providerRunnerTerminateIntentHonoredCount,\n providerRunnerTerminateIntentIssuedCount,\n reservationReleasedCount,\n} from '#metrics/instance.js';\nimport {config} from '../config.js';\n\nexport interface ReportRunnerInstancesParams {\n scope: 'installation' | 'workspace';\n workspaceId: string | null;\n provisionerId: string;\n events: RunnerInstanceReportEvent[];\n}\n\nexport function attachRunnerInstanceProviderId(params: {\n runnerInstanceId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n return attachRunnerInstanceProviderIdDb(params);\n}\n\nexport interface ReportRunnerInstancesResult {\n accepted: number;\n reservationsReleased: number;\n}\n\nexport interface ReconcileRunnerInstancesParams {\n workspaceId: string | null;\n provisionerId: string;\n observedRunnerInstanceIds: string[];\n}\n\nexport type ReconcileDesiredIntent = 'keep' | 'terminate';\ntype ReconcileDesiredIntentReason = 'job-cancelled' | 'terminal-state';\n\nexport interface ReconciledBoundJobExecution {\n jobId: string;\n jobExecutionId: string;\n workflowRunAttemptId: string;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport interface ReconciledRunnerInstance {\n providerRunnerId: string;\n state: RunnerInstanceState | null;\n reservationId: string | null;\n runnerSessionId: string | null;\n boundJobExecution: ReconciledBoundJobExecution | null;\n desiredIntent: ReconcileDesiredIntent;\n desiredIntentReason: ReconcileDesiredIntentReason | null;\n}\n\nexport interface ReconcileRunnerInstancesResult {\n runners: ReconciledRunnerInstance[];\n terminatedAbsentRunnerInstanceIds: string[];\n}\n\nexport type ActiveRunnerState = 'starting' | 'running' | 'stopping' | 'busy';\n\nexport interface ActiveRunner {\n runnerSessionId: string | null;\n providerRunnerId: string | null;\n provisionerId: string | null;\n state: ActiveRunnerState;\n labels: string[];\n templateKey: string | null;\n providerKind: string | null;\n jobId: string | null;\n workflowRunAttemptId: string | null;\n projectId: string | null;\n reportedAt: Date | null;\n lastHeartbeatAt: Date | null;\n}\n\nexport async function reportRunnerInstances(\n params: ReportRunnerInstancesParams,\n): Promise<ReportRunnerInstancesResult> {\n const result = await reportRunnerInstancesDb(params);\n\n for (const event of params.events) {\n providerRunnerReportCount.add(1, {state: event.state});\n }\n for (const intent of result.terminateIntentsHonored) {\n providerRunnerTerminateIntentHonoredCount.add(1, {reason: intent.reason});\n }\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n\n return result;\n}\n\nexport async function reconcileRunnerInstances(\n params: ReconcileRunnerInstancesParams,\n): Promise<ReconcileRunnerInstancesResult> {\n const result = await reconcileRunnerInstancesDb({\n ...params,\n terminateGraceSeconds: config.RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS,\n });\n\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n providerRunnerReconcileCallCount.add(1);\n if (result.absentIds.length > 0) providerRunnerAbsentTerminatedCount.add(result.absentIds.length);\n\n const runners = reconcileRunnerInstancesFromDbResult({\n observedRunnerInstanceIds: params.observedRunnerInstanceIds,\n observedRows: result.observedRows,\n boundJobExecutionsByRunnerInstanceId: result.boundJobExecutionsByRunnerInstanceId,\n });\n for (const runner of runners) {\n if (runner.desiredIntentReason) {\n providerRunnerTerminateIntentIssuedCount.add(1, {\n surface: 'reconcile',\n reason: runner.desiredIntentReason,\n });\n }\n }\n\n return {\n runners,\n terminatedAbsentRunnerInstanceIds: result.absentIds,\n };\n}\n\nexport function reconcileRunnerInstancesFromDbResult(params: {\n observedRunnerInstanceIds: string[];\n observedRows: RunnerInstance[];\n boundJobExecutionsByRunnerInstanceId: Map<string, RunnerInstanceBoundJobExecution>;\n}): ReconciledRunnerInstance[] {\n const rowsByRunnerInstanceId = new Map(\n params.observedRows.map((row) => [row.providerRunnerId, row]),\n );\n\n return params.observedRunnerInstanceIds.map((providerRunnerId) => {\n const row = rowsByRunnerInstanceId.get(providerRunnerId);\n const boundJobExecution = params.boundJobExecutionsByRunnerInstanceId.get(providerRunnerId);\n\n const desiredIntentReason = getDesiredIntentReason(row, boundJobExecution);\n\n return {\n providerRunnerId,\n state: row?.state ?? null,\n reservationId: row?.reservationId ?? null,\n runnerSessionId: row?.runnerSessionId ?? null,\n boundJobExecution: boundJobExecution\n ? toReconciledBoundJobExecution(boundJobExecution)\n : null,\n desiredIntent: desiredIntentReason ? 'terminate' : 'keep',\n desiredIntentReason,\n };\n });\n}\n\nexport async function listActiveRunners(params: {workspaceId: string}): Promise<ActiveRunner[]> {\n const [providerRunnerRows, jobExecutionRows] = await Promise.all([\n listActiveRunnerInstances({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n listActiveRunningJobExecutions({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n ]);\n\n return mergeActiveRunners(providerRunnerRows, jobExecutionRows);\n}\n\nfunction toReconciledBoundJobExecution(\n jobExecution: RunnerInstanceBoundJobExecution,\n): ReconciledBoundJobExecution {\n return {\n jobId: jobExecution.jobId,\n jobExecutionId: jobExecution.jobExecutionId,\n workflowRunAttemptId: jobExecution.workflowRunAttemptId,\n lastHeartbeatAt: jobExecution.lastHeartbeatAt,\n cancellationRequestedAt: jobExecution.cancellationRequestedAt,\n };\n}\n\nexport function desiredIntent(\n row: RunnerInstance | undefined,\n boundJobExecution: RunnerInstanceBoundJobExecution | undefined,\n): ReconcileDesiredIntent {\n return getDesiredIntentReason(row, boundJobExecution) ? 'terminate' : 'keep';\n}\n\nfunction getDesiredIntentReason(\n row: RunnerInstance | undefined,\n boundJobExecution: RunnerInstanceBoundJobExecution | undefined,\n): ReconcileDesiredIntentReason | null {\n if (!row) return null;\n if (isTerminalState(row.state)) return 'terminal-state';\n if (boundJobExecution?.cancellationRequestedAt) return 'job-cancelled';\n return null;\n}\n\nfunction mergeActiveRunners(\n providerRunners: RunnerInstance[],\n jobExecutions: ActiveRunningJobExecution[],\n): ActiveRunner[] {\n const jobExecutionsByRunnerSessionId = new Map<string, ActiveRunningJobExecution[]>();\n const jobExecutionsByRunnerInstanceId = new Map<string, ActiveRunningJobExecution[]>();\n for (const jobExecution of jobExecutions) {\n const runnerJobExecutions =\n jobExecutionsByRunnerSessionId.get(jobExecution.runnerSessionId) ?? [];\n runnerJobExecutions.push(jobExecution);\n jobExecutionsByRunnerSessionId.set(jobExecution.runnerSessionId, runnerJobExecutions);\n\n if (jobExecution.provisionerId && jobExecution.providerRunnerId) {\n const key = providerRunnerKey(jobExecution.provisionerId, jobExecution.providerRunnerId);\n const providerRunnerJobExecutions = jobExecutionsByRunnerInstanceId.get(key) ?? [];\n providerRunnerJobExecutions.push(jobExecution);\n jobExecutionsByRunnerInstanceId.set(key, providerRunnerJobExecutions);\n }\n }\n\n const merged: ActiveRunner[] = [];\n const usedJobExecutionIds = new Set<string>();\n\n for (const providerRunner of providerRunners) {\n const providerRunnerJobExecutions =\n jobExecutionsByRunnerInstanceId.get(\n providerRunnerKey(providerRunner.provisionerId, providerRunner.providerRunnerId),\n ) ??\n (providerRunner.runnerSessionId\n ? jobExecutionsByRunnerSessionId.get(providerRunner.runnerSessionId)\n : undefined);\n if (!providerRunnerJobExecutions || providerRunnerJobExecutions.length === 0) {\n merged.push(toActiveRunner(providerRunner, undefined));\n continue;\n }\n\n let emitted = false;\n for (const jobExecution of providerRunnerJobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n usedJobExecutionIds.add(jobExecution.jobExecutionId);\n merged.push(toActiveRunner(providerRunner, jobExecution));\n emitted = true;\n }\n if (!emitted) merged.push(toActiveRunner(providerRunner, undefined));\n }\n\n for (const jobExecution of jobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n merged.push(toActiveRunner(undefined, jobExecution));\n }\n\n return merged.sort(compareActiveRunners);\n}\n\nfunction providerRunnerKey(provisionerId: string, providerRunnerId: string): string {\n return `${provisionerId}:${providerRunnerId}`;\n}\n\nfunction toActiveRunner(\n providerRunner: RunnerInstance | undefined,\n jobExecution: ActiveRunningJobExecution | undefined,\n): ActiveRunner {\n return {\n runnerSessionId: providerRunner?.runnerSessionId ?? jobExecution?.runnerSessionId ?? null,\n providerRunnerId: providerRunner?.providerRunnerId ?? jobExecution?.providerRunnerId ?? null,\n provisionerId: providerRunner?.provisionerId ?? jobExecution?.provisionerId ?? null,\n state: jobExecution ? 'busy' : toActiveRunnerState(providerRunner?.state ?? 'running'),\n labels: providerRunner?.labels ?? jobExecution?.runnerLabels ?? [],\n templateKey: providerRunner?.templateKey ?? null,\n providerKind: providerRunner?.providerKind ?? null,\n jobId: jobExecution?.jobId ?? null,\n workflowRunAttemptId: jobExecution?.workflowRunAttemptId ?? null,\n projectId: jobExecution?.projectId ?? null,\n reportedAt: providerRunner?.reportedAt ?? null,\n lastHeartbeatAt: jobExecution?.lastHeartbeatAt ?? null,\n };\n}\n\nfunction toActiveRunnerState(state: RunnerInstanceState): ActiveRunnerState {\n if (state === 'starting' || state === 'stopping') return state;\n return 'running';\n}\n\nfunction compareActiveRunners(a: ActiveRunner, b: ActiveRunner): number {\n const aTime = Math.max(a.lastHeartbeatAt?.getTime() ?? 0, a.reportedAt?.getTime() ?? 0);\n const bTime = Math.max(b.lastHeartbeatAt?.getTime() ?? 0, b.reportedAt?.getTime() ?? 0);\n return bTime - aTime;\n}\n"],"names":["attachRunnerInstanceProviderId","attachRunnerInstanceProviderIdDb","isTerminalState","listActiveRunnerInstances","listActiveRunningJobExecutions","reconcileRunnerInstances","reconcileRunnerInstancesDb","reportRunnerInstances","reportRunnerInstancesDb","providerRunnerAbsentTerminatedCount","providerRunnerReconcileCallCount","providerRunnerReportCount","providerRunnerTerminateIntentHonoredCount","providerRunnerTerminateIntentIssuedCount","reservationReleasedCount","config","params","result","event","events","add","state","intent","terminateIntentsHonored","reason","reservationsReleased","terminateGraceSeconds","RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS","absentIds","length","runners","reconcileRunnerInstancesFromDbResult","observedRunnerInstanceIds","observedRows","boundJobExecutionsByRunnerInstanceId","runner","desiredIntentReason","surface","terminatedAbsentRunnerInstanceIds","rowsByRunnerInstanceId","Map","map","row","providerRunnerId","get","boundJobExecution","getDesiredIntentReason","reservationId","runnerSessionId","toReconciledBoundJobExecution","desiredIntent","listActiveRunners","providerRunnerRows","jobExecutionRows","Promise","all","workspaceId","windowSeconds","RUNNER_ACTIVE_WINDOW_SECONDS","mergeActiveRunners","jobExecution","jobId","jobExecutionId","workflowRunAttemptId","lastHeartbeatAt","cancellationRequestedAt","providerRunners","jobExecutions","jobExecutionsByRunnerSessionId","jobExecutionsByRunnerInstanceId","runnerJobExecutions","push","set","provisionerId","key","providerRunnerKey","providerRunnerJobExecutions","merged","usedJobExecutionIds","Set","providerRunner","undefined","toActiveRunner","emitted","has","sort","compareActiveRunners","toActiveRunnerState","labels","runnerLabels","templateKey","providerKind","projectId","reportedAt","a","b","aTime","Math","max","getTime","bTime"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/core/runner-instances.ts"],"sourcesContent":["import type {RunnerInstance, RunnerInstanceState} from '#core/entities/runner-instance.js';\nimport {\n attachRunnerInstanceProviderId as attachRunnerInstanceProviderIdDb,\n isTerminalState,\n listActiveRunnerInstances,\n listActiveRunningJobExecutions,\n type RunnerInstanceReportEvent,\n reconcileRunnerInstances as reconcileRunnerInstancesDb,\n reportRunnerInstances as reportRunnerInstancesDb,\n} from '#db/index.js';\nimport type {\n ActiveRunningJobExecution,\n RunnerInstanceBoundJobExecution,\n} from '#db/job-executions.js';\nimport {\n providerRunnerAbsentTerminatedCount,\n providerRunnerReconcileCallCount,\n providerRunnerReportCount,\n providerRunnerTerminateIntentHonoredCount,\n providerRunnerTerminateIntentIssuedCount,\n reservationReleasedCount,\n} from '#metrics/instance.js';\nimport {config} from '../config.js';\n\nexport interface ReportRunnerInstancesParams {\n scope: 'installation' | 'workspace';\n workspaceId: string | null;\n provisionerId: string;\n events: RunnerInstanceReportEvent[];\n}\n\nexport function attachRunnerInstanceProviderId(params: {\n runnerInstanceId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n return attachRunnerInstanceProviderIdDb(params);\n}\n\nexport interface ReportRunnerInstancesResult {\n accepted: number;\n reservationsReleased: number;\n}\n\nexport interface ReconcileRunnerInstancesParams {\n workspaceId: string | null;\n provisionerId: string;\n observedRunnerInstanceIds: string[];\n}\n\nexport type ReconcileDesiredIntent = 'keep' | 'terminate';\ntype ReconcileDesiredIntentReason = 'job-cancelled' | 'terminal-state';\n\nexport interface ReconciledBoundJobExecution {\n jobId: string;\n jobExecutionId: string;\n workflowRunAttemptId: string;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport interface ReconciledRunnerInstance {\n providerRunnerId: string;\n state: RunnerInstanceState | null;\n intendedReservationId: string | null;\n reservationId: string | null;\n runnerSessionId: string | null;\n boundJobExecution: ReconciledBoundJobExecution | null;\n desiredIntent: ReconcileDesiredIntent;\n desiredIntentReason: ReconcileDesiredIntentReason | null;\n}\n\nexport interface ReconcileRunnerInstancesResult {\n runners: ReconciledRunnerInstance[];\n terminatedAbsentRunnerInstanceIds: string[];\n}\n\nexport type ActiveRunnerState = 'starting' | 'running' | 'stopping' | 'busy';\n\nexport interface ActiveRunner {\n runnerSessionId: string | null;\n providerRunnerId: string | null;\n provisionerId: string | null;\n state: ActiveRunnerState;\n labels: string[];\n templateKey: string | null;\n providerKind: string | null;\n jobId: string | null;\n workflowRunAttemptId: string | null;\n projectId: string | null;\n reportedAt: Date | null;\n lastHeartbeatAt: Date | null;\n}\n\nexport async function reportRunnerInstances(\n params: ReportRunnerInstancesParams,\n): Promise<ReportRunnerInstancesResult> {\n const result = await reportRunnerInstancesDb(params);\n\n for (const event of params.events) {\n providerRunnerReportCount.add(1, {state: event.state});\n }\n for (const intent of result.terminateIntentsHonored) {\n providerRunnerTerminateIntentHonoredCount.add(1, {reason: intent.reason});\n }\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n\n return result;\n}\n\nexport async function reconcileRunnerInstances(\n params: ReconcileRunnerInstancesParams,\n): Promise<ReconcileRunnerInstancesResult> {\n const result = await reconcileRunnerInstancesDb({\n ...params,\n terminateGraceSeconds: config.RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS,\n });\n\n if (result.reservationsReleased > 0) reservationReleasedCount.add(result.reservationsReleased);\n providerRunnerReconcileCallCount.add(1);\n if (result.absentIds.length > 0) providerRunnerAbsentTerminatedCount.add(result.absentIds.length);\n\n const runners = reconcileRunnerInstancesFromDbResult({\n observedRunnerInstanceIds: params.observedRunnerInstanceIds,\n observedRows: result.observedRows,\n boundJobExecutionsByRunnerInstanceId: result.boundJobExecutionsByRunnerInstanceId,\n });\n for (const runner of runners) {\n if (runner.desiredIntentReason) {\n providerRunnerTerminateIntentIssuedCount.add(1, {\n surface: 'reconcile',\n reason: runner.desiredIntentReason,\n });\n }\n }\n\n return {\n runners,\n terminatedAbsentRunnerInstanceIds: result.absentIds,\n };\n}\n\nexport function reconcileRunnerInstancesFromDbResult(params: {\n observedRunnerInstanceIds: string[];\n observedRows: RunnerInstance[];\n boundJobExecutionsByRunnerInstanceId: Map<string, RunnerInstanceBoundJobExecution>;\n}): ReconciledRunnerInstance[] {\n const rowsByRunnerInstanceId = new Map(\n params.observedRows.map((row) => [row.providerRunnerId, row]),\n );\n\n return params.observedRunnerInstanceIds.map((providerRunnerId) => {\n const row = rowsByRunnerInstanceId.get(providerRunnerId);\n const boundJobExecution = params.boundJobExecutionsByRunnerInstanceId.get(providerRunnerId);\n\n const desiredIntentReason = getDesiredIntentReason(row, boundJobExecution);\n\n return {\n providerRunnerId,\n state: row?.state ?? null,\n intendedReservationId: row?.intendedReservationId ?? null,\n reservationId: row?.reservationId ?? null,\n runnerSessionId: row?.runnerSessionId ?? null,\n boundJobExecution: boundJobExecution\n ? toReconciledBoundJobExecution(boundJobExecution)\n : null,\n desiredIntent: desiredIntentReason ? 'terminate' : 'keep',\n desiredIntentReason,\n };\n });\n}\n\nexport async function listActiveRunners(params: {workspaceId: string}): Promise<ActiveRunner[]> {\n const [providerRunnerRows, jobExecutionRows] = await Promise.all([\n listActiveRunnerInstances({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n listActiveRunningJobExecutions({\n workspaceId: params.workspaceId,\n windowSeconds: config.RUNNER_ACTIVE_WINDOW_SECONDS,\n }),\n ]);\n\n return mergeActiveRunners(providerRunnerRows, jobExecutionRows);\n}\n\nfunction toReconciledBoundJobExecution(\n jobExecution: RunnerInstanceBoundJobExecution,\n): ReconciledBoundJobExecution {\n return {\n jobId: jobExecution.jobId,\n jobExecutionId: jobExecution.jobExecutionId,\n workflowRunAttemptId: jobExecution.workflowRunAttemptId,\n lastHeartbeatAt: jobExecution.lastHeartbeatAt,\n cancellationRequestedAt: jobExecution.cancellationRequestedAt,\n };\n}\n\nexport function desiredIntent(\n row: RunnerInstance | undefined,\n boundJobExecution: RunnerInstanceBoundJobExecution | undefined,\n): ReconcileDesiredIntent {\n return getDesiredIntentReason(row, boundJobExecution) ? 'terminate' : 'keep';\n}\n\nfunction getDesiredIntentReason(\n row: RunnerInstance | undefined,\n boundJobExecution: RunnerInstanceBoundJobExecution | undefined,\n): ReconcileDesiredIntentReason | null {\n if (!row) return null;\n if (isTerminalState(row.state)) return 'terminal-state';\n if (boundJobExecution?.cancellationRequestedAt) return 'job-cancelled';\n return null;\n}\n\nfunction mergeActiveRunners(\n providerRunners: RunnerInstance[],\n jobExecutions: ActiveRunningJobExecution[],\n): ActiveRunner[] {\n const jobExecutionsByRunnerSessionId = new Map<string, ActiveRunningJobExecution[]>();\n const jobExecutionsByRunnerInstanceId = new Map<string, ActiveRunningJobExecution[]>();\n for (const jobExecution of jobExecutions) {\n const runnerJobExecutions =\n jobExecutionsByRunnerSessionId.get(jobExecution.runnerSessionId) ?? [];\n runnerJobExecutions.push(jobExecution);\n jobExecutionsByRunnerSessionId.set(jobExecution.runnerSessionId, runnerJobExecutions);\n\n if (jobExecution.provisionerId && jobExecution.providerRunnerId) {\n const key = providerRunnerKey(jobExecution.provisionerId, jobExecution.providerRunnerId);\n const providerRunnerJobExecutions = jobExecutionsByRunnerInstanceId.get(key) ?? [];\n providerRunnerJobExecutions.push(jobExecution);\n jobExecutionsByRunnerInstanceId.set(key, providerRunnerJobExecutions);\n }\n }\n\n const merged: ActiveRunner[] = [];\n const usedJobExecutionIds = new Set<string>();\n\n for (const providerRunner of providerRunners) {\n const providerRunnerJobExecutions =\n jobExecutionsByRunnerInstanceId.get(\n providerRunnerKey(providerRunner.provisionerId, providerRunner.providerRunnerId),\n ) ??\n (providerRunner.runnerSessionId\n ? jobExecutionsByRunnerSessionId.get(providerRunner.runnerSessionId)\n : undefined);\n if (!providerRunnerJobExecutions || providerRunnerJobExecutions.length === 0) {\n merged.push(toActiveRunner(providerRunner, undefined));\n continue;\n }\n\n let emitted = false;\n for (const jobExecution of providerRunnerJobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n usedJobExecutionIds.add(jobExecution.jobExecutionId);\n merged.push(toActiveRunner(providerRunner, jobExecution));\n emitted = true;\n }\n if (!emitted) merged.push(toActiveRunner(providerRunner, undefined));\n }\n\n for (const jobExecution of jobExecutions) {\n if (usedJobExecutionIds.has(jobExecution.jobExecutionId)) continue;\n merged.push(toActiveRunner(undefined, jobExecution));\n }\n\n return merged.sort(compareActiveRunners);\n}\n\nfunction providerRunnerKey(provisionerId: string, providerRunnerId: string): string {\n return `${provisionerId}:${providerRunnerId}`;\n}\n\nfunction toActiveRunner(\n providerRunner: RunnerInstance | undefined,\n jobExecution: ActiveRunningJobExecution | undefined,\n): ActiveRunner {\n return {\n runnerSessionId: providerRunner?.runnerSessionId ?? jobExecution?.runnerSessionId ?? null,\n providerRunnerId: providerRunner?.providerRunnerId ?? jobExecution?.providerRunnerId ?? null,\n provisionerId: providerRunner?.provisionerId ?? jobExecution?.provisionerId ?? null,\n state: jobExecution ? 'busy' : toActiveRunnerState(providerRunner?.state ?? 'running'),\n labels: providerRunner?.labels ?? jobExecution?.runnerLabels ?? [],\n templateKey: providerRunner?.templateKey ?? null,\n providerKind: providerRunner?.providerKind ?? null,\n jobId: jobExecution?.jobId ?? null,\n workflowRunAttemptId: jobExecution?.workflowRunAttemptId ?? null,\n projectId: jobExecution?.projectId ?? null,\n reportedAt: providerRunner?.reportedAt ?? null,\n lastHeartbeatAt: jobExecution?.lastHeartbeatAt ?? null,\n };\n}\n\nfunction toActiveRunnerState(state: RunnerInstanceState): ActiveRunnerState {\n if (state === 'starting' || state === 'stopping') return state;\n return 'running';\n}\n\nfunction compareActiveRunners(a: ActiveRunner, b: ActiveRunner): number {\n const aTime = Math.max(a.lastHeartbeatAt?.getTime() ?? 0, a.reportedAt?.getTime() ?? 0);\n const bTime = Math.max(b.lastHeartbeatAt?.getTime() ?? 0, b.reportedAt?.getTime() ?? 0);\n return bTime - aTime;\n}\n"],"names":["attachRunnerInstanceProviderId","attachRunnerInstanceProviderIdDb","isTerminalState","listActiveRunnerInstances","listActiveRunningJobExecutions","reconcileRunnerInstances","reconcileRunnerInstancesDb","reportRunnerInstances","reportRunnerInstancesDb","providerRunnerAbsentTerminatedCount","providerRunnerReconcileCallCount","providerRunnerReportCount","providerRunnerTerminateIntentHonoredCount","providerRunnerTerminateIntentIssuedCount","reservationReleasedCount","config","params","result","event","events","add","state","intent","terminateIntentsHonored","reason","reservationsReleased","terminateGraceSeconds","RUNNER_RECONCILE_TERMINATE_GRACE_SECONDS","absentIds","length","runners","reconcileRunnerInstancesFromDbResult","observedRunnerInstanceIds","observedRows","boundJobExecutionsByRunnerInstanceId","runner","desiredIntentReason","surface","terminatedAbsentRunnerInstanceIds","rowsByRunnerInstanceId","Map","map","row","providerRunnerId","get","boundJobExecution","getDesiredIntentReason","intendedReservationId","reservationId","runnerSessionId","toReconciledBoundJobExecution","desiredIntent","listActiveRunners","providerRunnerRows","jobExecutionRows","Promise","all","workspaceId","windowSeconds","RUNNER_ACTIVE_WINDOW_SECONDS","mergeActiveRunners","jobExecution","jobId","jobExecutionId","workflowRunAttemptId","lastHeartbeatAt","cancellationRequestedAt","providerRunners","jobExecutions","jobExecutionsByRunnerSessionId","jobExecutionsByRunnerInstanceId","runnerJobExecutions","push","set","provisionerId","key","providerRunnerKey","providerRunnerJobExecutions","merged","usedJobExecutionIds","Set","providerRunner","undefined","toActiveRunner","emitted","has","sort","compareActiveRunners","toActiveRunnerState","labels","runnerLabels","templateKey","providerKind","projectId","reportedAt","a","b","aTime","Math","max","getTime","bTime"],"mappings":"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"}
|
package/dist/db/db.d.ts
CHANGED
|
@@ -614,6 +614,23 @@ export declare const schema: {
|
|
|
614
614
|
identity: undefined;
|
|
615
615
|
generated: undefined;
|
|
616
616
|
}, {}, {}>;
|
|
617
|
+
launchKind: import("drizzle-orm/pg-core").PgColumn<{
|
|
618
|
+
name: "launch_kind";
|
|
619
|
+
tableName: "runner_instances";
|
|
620
|
+
dataType: "string";
|
|
621
|
+
columnType: "PgEnumColumn";
|
|
622
|
+
data: "demand" | "manual" | "warm";
|
|
623
|
+
driverParam: string;
|
|
624
|
+
notNull: true;
|
|
625
|
+
hasDefault: true;
|
|
626
|
+
isPrimaryKey: false;
|
|
627
|
+
isAutoincrement: false;
|
|
628
|
+
hasRuntimeDefault: false;
|
|
629
|
+
enumValues: ["demand", "warm", "manual"];
|
|
630
|
+
baseColumn: never;
|
|
631
|
+
identity: undefined;
|
|
632
|
+
generated: undefined;
|
|
633
|
+
}, {}, {}>;
|
|
617
634
|
assignedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
618
635
|
name: "assigned_at";
|
|
619
636
|
tableName: "runner_instances";
|
|
@@ -1675,6 +1692,23 @@ export declare const schema: {
|
|
|
1675
1692
|
identity: undefined;
|
|
1676
1693
|
generated: undefined;
|
|
1677
1694
|
}, {}, {}>;
|
|
1695
|
+
kind: import("drizzle-orm/pg-core").PgColumn<{
|
|
1696
|
+
name: "kind";
|
|
1697
|
+
tableName: "reservations";
|
|
1698
|
+
dataType: "string";
|
|
1699
|
+
columnType: "PgEnumColumn";
|
|
1700
|
+
data: "bound" | "launch";
|
|
1701
|
+
driverParam: string;
|
|
1702
|
+
notNull: true;
|
|
1703
|
+
hasDefault: true;
|
|
1704
|
+
isPrimaryKey: false;
|
|
1705
|
+
isAutoincrement: false;
|
|
1706
|
+
hasRuntimeDefault: false;
|
|
1707
|
+
enumValues: ["bound", "launch"];
|
|
1708
|
+
baseColumn: never;
|
|
1709
|
+
identity: undefined;
|
|
1710
|
+
generated: undefined;
|
|
1711
|
+
}, {}, {}>;
|
|
1678
1712
|
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
1679
1713
|
name: "created_at";
|
|
1680
1714
|
tableName: "reservations";
|
|
@@ -3835,6 +3869,23 @@ export declare function db(): NodePgDatabase<{
|
|
|
3835
3869
|
identity: undefined;
|
|
3836
3870
|
generated: undefined;
|
|
3837
3871
|
}, {}, {}>;
|
|
3872
|
+
launchKind: import("drizzle-orm/pg-core").PgColumn<{
|
|
3873
|
+
name: "launch_kind";
|
|
3874
|
+
tableName: "runner_instances";
|
|
3875
|
+
dataType: "string";
|
|
3876
|
+
columnType: "PgEnumColumn";
|
|
3877
|
+
data: "demand" | "manual" | "warm";
|
|
3878
|
+
driverParam: string;
|
|
3879
|
+
notNull: true;
|
|
3880
|
+
hasDefault: true;
|
|
3881
|
+
isPrimaryKey: false;
|
|
3882
|
+
isAutoincrement: false;
|
|
3883
|
+
hasRuntimeDefault: false;
|
|
3884
|
+
enumValues: ["demand", "warm", "manual"];
|
|
3885
|
+
baseColumn: never;
|
|
3886
|
+
identity: undefined;
|
|
3887
|
+
generated: undefined;
|
|
3888
|
+
}, {}, {}>;
|
|
3838
3889
|
assignedAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
3839
3890
|
name: "assigned_at";
|
|
3840
3891
|
tableName: "runner_instances";
|
|
@@ -4896,6 +4947,23 @@ export declare function db(): NodePgDatabase<{
|
|
|
4896
4947
|
identity: undefined;
|
|
4897
4948
|
generated: undefined;
|
|
4898
4949
|
}, {}, {}>;
|
|
4950
|
+
kind: import("drizzle-orm/pg-core").PgColumn<{
|
|
4951
|
+
name: "kind";
|
|
4952
|
+
tableName: "reservations";
|
|
4953
|
+
dataType: "string";
|
|
4954
|
+
columnType: "PgEnumColumn";
|
|
4955
|
+
data: "bound" | "launch";
|
|
4956
|
+
driverParam: string;
|
|
4957
|
+
notNull: true;
|
|
4958
|
+
hasDefault: true;
|
|
4959
|
+
isPrimaryKey: false;
|
|
4960
|
+
isAutoincrement: false;
|
|
4961
|
+
hasRuntimeDefault: false;
|
|
4962
|
+
enumValues: ["bound", "launch"];
|
|
4963
|
+
baseColumn: never;
|
|
4964
|
+
identity: undefined;
|
|
4965
|
+
generated: undefined;
|
|
4966
|
+
}, {}, {}>;
|
|
4899
4967
|
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
4900
4968
|
name: "created_at";
|
|
4901
4969
|
tableName: "reservations";
|
package/dist/db/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAiBnE,eAAO,MAAM,MAAM
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAU,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAiBnE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgBlB,CAAC;AAIF,wBAAgB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAGjB;AAED,wBAAgB,OAAO,IAAI,IAAI,CAE9B;AAED,MAAM,MAAM,EAAE,GAAG,UAAU,CAAC,UAAU,CAAC,cAAc,CAAC,OAAO,MAAM,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ephemeral-registration-tokens.d.ts","sourceRoot":"","sources":["../../src/db/ephemeral-registration-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,gDAAgD,CAAC;AAuB/F,MAAM,WAAW,sCAAsC;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,yCAAyC;IACxD,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,4CAA4C;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,yCAAyC,EAAE,CAAC;CACnD;AAED,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,sCAAsC,GAC7C,OAAO,CAAC,0BAA0B,CAAC,CAiDrC;AAED,wBAAsB,sCAAsC,CAC1D,MAAM,EAAE,4CAA4C,GACnD,OAAO,CAAC,0BAA0B,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"ephemeral-registration-tokens.d.ts","sourceRoot":"","sources":["../../src/db/ephemeral-registration-tokens.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAExE,OAAO,KAAK,EAAC,0BAA0B,EAAC,MAAM,gDAAgD,CAAC;AAuB/F,MAAM,WAAW,sCAAsC;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC1C,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,yCAAyC;IACxD,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,4CAA4C;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,IAAI,CAAC;IAChB,IAAI,EAAE,yCAAyC,EAAE,CAAC;CACnD;AAED,wBAAsB,gCAAgC,CACpD,MAAM,EAAE,sCAAsC,GAC7C,OAAO,CAAC,0BAA0B,CAAC,CAiDrC;AAED,wBAAsB,sCAAsC,CAC1D,MAAM,EAAE,4CAA4C,GACnD,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAqGvC;AAED,wBAAsB,uCAAuC,CAC3D,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,0BAA0B,GAAG,SAAS,CAAC,CAUjD;AAED,MAAM,WAAW,8CAA8C;IAC7D,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,wBAAsB,wCAAwC,CAC5D,MAAM,EAAE,8CAA8C,GACrD,OAAO,CAAC,MAAM,CAAC,CAqBjB;AAED,wBAAsB,0CAA0C,CAAC,MAAM,EAAE;IACvE,gBAAgB,EAAE,MAAM,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IACpD,SAAS,EAAE,MAAM,CAAC;CACnB,qDAiGA"}
|
|
@@ -58,7 +58,7 @@ export async function createEphemeralRegistrationTokensBatch(params) {
|
|
|
58
58
|
const [reservation] = await tx.select({
|
|
59
59
|
count: reservations.count,
|
|
60
60
|
isExpired: sql`${reservations.expiresAt} <= now()`
|
|
61
|
-
}).from(reservations).where(and(eq(reservations.id, params.reservationId), eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId))).limit(1);
|
|
61
|
+
}).from(reservations).where(and(eq(reservations.id, params.reservationId), eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId), eq(reservations.kind, 'launch'))).limit(1);
|
|
62
62
|
if (!reservation) throw new ReservationNotFoundError(params.reservationId);
|
|
63
63
|
if (reservation.isExpired) throw new ReservationExpiredError(params.reservationId);
|
|
64
64
|
if (params.rows.length > reservation.count) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/ephemeral-registration-tokens.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {and, asc, eq, gt, inArray, isNull, lt, sql} from 'drizzle-orm';\nimport type {EphemeralRegistrationToken} from '#core/entities/ephemeral-registration-token.js';\nimport {\n ActiveEphemeralRegistrationTokenExistsError,\n ActiveEphemeralRegistrationTokensExistError,\n EmptyRunnerLabelsError,\n RegistrationTokenBatchExceedsReservationError,\n RegistrationTokenConsumedError,\n RegistrationTokenExpiredError,\n RegistrationTokenWorkspaceMismatchError,\n ReservationExpiredError,\n ReservationNotFoundError,\n} from '#core/errors.js';\nimport {sanitizeRunnerLabelsOrThrow} from '#core/runner-labels.js';\nimport {db} from './db.js';\nimport {\n ephemeralRegistrationTokens,\n toEphemeralRegistrationToken,\n} from './schema/ephemeral-registration-tokens.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions, toRunnerSession} from './schema/runner-sessions.js';\n\nexport interface CreateEphemeralRegistrationTokenParams {\n workspaceId: string;\n provisionerId: string;\n reservationId?: string | null | undefined;\n providerRunnerId: string;\n hashedToken: string;\n prefix: string;\n expiresAt: Date;\n}\n\nexport interface CreateEphemeralRegistrationTokensBatchRow {\n providerRunnerId: string;\n hashedToken: string;\n prefix: string;\n}\n\nexport interface CreateEphemeralRegistrationTokensBatchParams {\n workspaceId: string;\n provisionerId: string;\n reservationId: string;\n expiresAt: Date;\n rows: CreateEphemeralRegistrationTokensBatchRow[];\n}\n\nexport async function createEphemeralRegistrationToken(\n params: CreateEphemeralRegistrationTokenParams,\n): Promise<EphemeralRegistrationToken> {\n const rows = await db().transaction(async (tx) => {\n const providerRunnerLockKey = [\n 'runners_ephemeral_registration_tokens',\n params.workspaceId,\n params.provisionerId,\n params.providerRunnerId,\n ].join(':');\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${providerRunnerLockKey}))`);\n\n const [active] = await tx\n .select({id: ephemeralRegistrationTokens.id})\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n eq(ephemeralRegistrationTokens.providerRunnerId, params.providerRunnerId),\n isNull(ephemeralRegistrationTokens.consumedAt),\n gt(ephemeralRegistrationTokens.expiresAt, sql`now()`),\n ),\n )\n .limit(1);\n\n if (active) {\n throw new ActiveEphemeralRegistrationTokenExistsError(\n params.workspaceId,\n params.provisionerId,\n params.providerRunnerId,\n );\n }\n\n return await tx\n .insert(ephemeralRegistrationTokens)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n reservationId: params.reservationId ?? null,\n providerRunnerId: params.providerRunnerId,\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n expiresAt: params.expiresAt,\n })\n .returning();\n });\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n return toEphemeralRegistrationToken(row);\n}\n\nexport async function createEphemeralRegistrationTokensBatch(\n params: CreateEphemeralRegistrationTokensBatchParams,\n): Promise<EphemeralRegistrationToken[]> {\n const rows = await db().transaction(async (tx) => {\n const provisionerLockKey = [\n 'runners_ephemeral_registration_tokens',\n params.workspaceId,\n params.provisionerId,\n ].join(':');\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${provisionerLockKey}))`);\n for (const providerRunnerId of [\n ...new Set(params.rows.map((row) => row.providerRunnerId)),\n ].sort()) {\n const providerRunnerLockKey = [\n 'runners_ephemeral_registration_tokens',\n params.workspaceId,\n params.provisionerId,\n providerRunnerId,\n ].join(':');\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${providerRunnerLockKey}))`);\n }\n\n const [reservation] = await tx\n .select({\n count: reservations.count,\n isExpired: sql<boolean>`${reservations.expiresAt} <= now()`,\n })\n .from(reservations)\n .where(\n and(\n eq(reservations.id, params.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n ),\n )\n .limit(1);\n\n if (!reservation) throw new ReservationNotFoundError(params.reservationId);\n if (reservation.isExpired) throw new ReservationExpiredError(params.reservationId);\n if (params.rows.length > reservation.count) {\n throw new RegistrationTokenBatchExceedsReservationError(\n params.rows.length,\n reservation.count,\n );\n }\n\n const [existingForReservation] = await tx\n .select({count: sql<number>`count(*)::int`})\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n eq(ephemeralRegistrationTokens.reservationId, params.reservationId),\n ),\n );\n const alreadyMinted = existingForReservation?.count ?? 0;\n if (alreadyMinted + params.rows.length > reservation.count) {\n throw new RegistrationTokenBatchExceedsReservationError(\n params.rows.length,\n reservation.count,\n alreadyMinted,\n );\n }\n\n const providerRunnerIds = params.rows.map((row) => row.providerRunnerId);\n const activeRows = await tx\n .select({providerRunnerId: ephemeralRegistrationTokens.providerRunnerId})\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n inArray(ephemeralRegistrationTokens.providerRunnerId, providerRunnerIds),\n isNull(ephemeralRegistrationTokens.consumedAt),\n gt(ephemeralRegistrationTokens.expiresAt, sql`now()`),\n ),\n );\n\n if (activeRows.length > 0) {\n throw new ActiveEphemeralRegistrationTokensExistError(\n activeRows.map((row) => row.providerRunnerId),\n );\n }\n\n return await tx\n .insert(ephemeralRegistrationTokens)\n .values(\n params.rows.map((row) => ({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n reservationId: params.reservationId,\n providerRunnerId: row.providerRunnerId,\n hashedToken: row.hashedToken,\n prefix: row.prefix,\n expiresAt: params.expiresAt,\n })),\n )\n .returning();\n });\n\n return rows.map(toEphemeralRegistrationToken);\n}\n\nexport async function resolveEphemeralRegistrationTokenByHash(\n hashedToken: string,\n): Promise<EphemeralRegistrationToken | undefined> {\n const rows = await db()\n .select()\n .from(ephemeralRegistrationTokens)\n .where(eq(ephemeralRegistrationTokens.hashedToken, hashedToken))\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toEphemeralRegistrationToken(row);\n}\n\nexport interface DeleteExpiredEphemeralRegistrationTokensParams {\n retentionDays: number;\n limit?: number;\n}\n\n/**\n * Deletes ephemeral registration tokens that have reached a terminal state and\n * outlived the retention window. A token is terminal once it is consumed\n * (single use spent) or expired without consumption; the retention window is\n * measured from that terminal event so the audit record survives a bounded\n * debugging window. Active tokens that are neither consumed nor expired are\n * never deleted, so a live single-use credential is never removed early.\n */\nexport async function deleteExpiredEphemeralRegistrationTokens(\n params: DeleteExpiredEphemeralRegistrationTokensParams,\n): Promise<number> {\n // coalesce(consumed_at, expires_at) is the terminal timestamp: consumed_at\n // when the token was spent, otherwise its expiry. Comparing it to the cutoff\n // both selects deletable rows and orders the batch, and it matches the\n // terminal index so idle GC ticks never scan live rows.\n const terminalAt = sql`coalesce(${ephemeralRegistrationTokens.consumedAt}, ${ephemeralRegistrationTokens.expiresAt})`;\n const retentionCutoff = sql`now() - (${params.retentionDays} || ' days')::interval`;\n\n const deletableIds = db()\n .select({id: ephemeralRegistrationTokens.id})\n .from(ephemeralRegistrationTokens)\n .where(lt(terminalAt, retentionCutoff))\n .orderBy(asc(terminalAt), asc(ephemeralRegistrationTokens.id))\n .limit(params.limit ?? 1000);\n\n const deleted = await db()\n .delete(ephemeralRegistrationTokens)\n .where(inArray(ephemeralRegistrationTokens.id, deletableIds))\n .returning({id: ephemeralRegistrationTokens.id});\n\n return deleted.length;\n}\n\nexport async function createRunnerSessionConsumingEphemeralToken(params: {\n ephemeralTokenId: string;\n workspaceId: string;\n labels: string[];\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n maxClaims: number;\n}) {\n return await db().transaction(async (tx) => {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);\n\n const consumed = await tx\n .update(ephemeralRegistrationTokens)\n .set({consumedAt: sql`now()`})\n .where(\n and(\n eq(ephemeralRegistrationTokens.id, params.ephemeralTokenId),\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n isNull(ephemeralRegistrationTokens.consumedAt),\n gt(ephemeralRegistrationTokens.expiresAt, sql`now()`),\n ),\n )\n .returning({\n id: ephemeralRegistrationTokens.id,\n provisionerId: ephemeralRegistrationTokens.provisionerId,\n providerRunnerId: ephemeralRegistrationTokens.providerRunnerId,\n });\n\n if (!consumed[0]) {\n const [token] = await tx\n .select({\n workspaceId: ephemeralRegistrationTokens.workspaceId,\n consumedAt: ephemeralRegistrationTokens.consumedAt,\n isExpired: sql<boolean>`${ephemeralRegistrationTokens.expiresAt} <= now()`,\n })\n .from(ephemeralRegistrationTokens)\n .where(eq(ephemeralRegistrationTokens.id, params.ephemeralTokenId))\n .limit(1);\n\n if (!token) {\n throw new Error(`Ephemeral registration token not found: ${params.ephemeralTokenId}`);\n }\n if (token.workspaceId !== params.workspaceId) {\n throw new RegistrationTokenWorkspaceMismatchError(\n params.ephemeralTokenId,\n params.workspaceId,\n );\n }\n if (token.consumedAt) throw new RegistrationTokenConsumedError(params.ephemeralTokenId);\n if (token.isExpired) throw new RegistrationTokenExpiredError(params.ephemeralTokenId);\n throw new Error(\n `Ephemeral registration token could not be consumed: ${params.ephemeralTokenId}`,\n );\n }\n\n const [provisioner] = await tx\n .select({scope: provisionerTokens.scope})\n .from(provisionerTokens)\n .where(eq(provisionerTokens.id, consumed[0].provisionerId))\n .limit(1);\n const labels = sanitizeRunnerLabelsOrThrow(params.labels, {\n scope: provisioner?.scope ?? 'workspace',\n source: 'ephemeral runner registration',\n });\n if (labels.length === 0) throw new EmptyRunnerLabelsError();\n\n const [session] = await tx\n .insert(runnerSessions)\n .values({\n workspaceId: params.workspaceId,\n scope: 'workspace',\n registrationTokenId: params.ephemeralTokenId,\n registrationTokenKind: 'ephemeral',\n provisionerId: consumed[0].provisionerId,\n providerRunnerId: consumed[0].providerRunnerId,\n labels,\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n maxClaims: params.maxClaims,\n claimsUsed: 0,\n })\n .returning();\n\n if (!session) throw new Error('Insert returned no rows');\n\n await tx\n .update(ephemeralRegistrationTokens)\n .set({consumedSessionId: session.id})\n .where(eq(ephemeralRegistrationTokens.id, params.ephemeralTokenId));\n\n await tx\n .update(providerRunners)\n .set({runnerSessionId: session.id, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, consumed[0].provisionerId),\n eq(providerRunners.providerRunnerId, consumed[0].providerRunnerId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n\n return toRunnerSession(session);\n });\n}\n"],"names":["and","asc","eq","gt","inArray","isNull","lt","sql","ActiveEphemeralRegistrationTokenExistsError","ActiveEphemeralRegistrationTokensExistError","EmptyRunnerLabelsError","RegistrationTokenBatchExceedsReservationError","RegistrationTokenConsumedError","RegistrationTokenExpiredError","RegistrationTokenWorkspaceMismatchError","ReservationExpiredError","ReservationNotFoundError","sanitizeRunnerLabelsOrThrow","db","ephemeralRegistrationTokens","toEphemeralRegistrationToken","provisionerTokens","reservations","providerRunners","runnerSessions","toRunnerSession","createEphemeralRegistrationToken","params","rows","transaction","tx","providerRunnerLockKey","workspaceId","provisionerId","providerRunnerId","join","execute","active","select","id","from","where","consumedAt","expiresAt","limit","insert","values","reservationId","hashedToken","prefix","returning","row","Error","createEphemeralRegistrationTokensBatch","provisionerLockKey","Set","map","sort","reservation","count","isExpired","length","existingForReservation","alreadyMinted","providerRunnerIds","activeRows","resolveEphemeralRegistrationTokenByHash","undefined","deleteExpiredEphemeralRegistrationTokens","terminalAt","retentionCutoff","retentionDays","deletableIds","orderBy","deleted","delete","createRunnerSessionConsumingEphemeralToken","consumed","update","set","ephemeralTokenId","token","provisioner","scope","labels","source","session","registrationTokenId","registrationTokenKind","toolCapabilities","toolCapabilitiesReportedAt","maxClaims","claimsUsed","consumedSessionId","runnerSessionId","updatedAt","reservationReleasedAt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/ephemeral-registration-tokens.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {and, asc, eq, gt, inArray, isNull, lt, sql} from 'drizzle-orm';\nimport type {EphemeralRegistrationToken} from '#core/entities/ephemeral-registration-token.js';\nimport {\n ActiveEphemeralRegistrationTokenExistsError,\n ActiveEphemeralRegistrationTokensExistError,\n EmptyRunnerLabelsError,\n RegistrationTokenBatchExceedsReservationError,\n RegistrationTokenConsumedError,\n RegistrationTokenExpiredError,\n RegistrationTokenWorkspaceMismatchError,\n ReservationExpiredError,\n ReservationNotFoundError,\n} from '#core/errors.js';\nimport {sanitizeRunnerLabelsOrThrow} from '#core/runner-labels.js';\nimport {db} from './db.js';\nimport {\n ephemeralRegistrationTokens,\n toEphemeralRegistrationToken,\n} from './schema/ephemeral-registration-tokens.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\nimport {providerRunners} from './schema/runner-instances.js';\nimport {runnerSessions, toRunnerSession} from './schema/runner-sessions.js';\n\nexport interface CreateEphemeralRegistrationTokenParams {\n workspaceId: string;\n provisionerId: string;\n reservationId?: string | null | undefined;\n providerRunnerId: string;\n hashedToken: string;\n prefix: string;\n expiresAt: Date;\n}\n\nexport interface CreateEphemeralRegistrationTokensBatchRow {\n providerRunnerId: string;\n hashedToken: string;\n prefix: string;\n}\n\nexport interface CreateEphemeralRegistrationTokensBatchParams {\n workspaceId: string;\n provisionerId: string;\n reservationId: string;\n expiresAt: Date;\n rows: CreateEphemeralRegistrationTokensBatchRow[];\n}\n\nexport async function createEphemeralRegistrationToken(\n params: CreateEphemeralRegistrationTokenParams,\n): Promise<EphemeralRegistrationToken> {\n const rows = await db().transaction(async (tx) => {\n const providerRunnerLockKey = [\n 'runners_ephemeral_registration_tokens',\n params.workspaceId,\n params.provisionerId,\n params.providerRunnerId,\n ].join(':');\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${providerRunnerLockKey}))`);\n\n const [active] = await tx\n .select({id: ephemeralRegistrationTokens.id})\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n eq(ephemeralRegistrationTokens.providerRunnerId, params.providerRunnerId),\n isNull(ephemeralRegistrationTokens.consumedAt),\n gt(ephemeralRegistrationTokens.expiresAt, sql`now()`),\n ),\n )\n .limit(1);\n\n if (active) {\n throw new ActiveEphemeralRegistrationTokenExistsError(\n params.workspaceId,\n params.provisionerId,\n params.providerRunnerId,\n );\n }\n\n return await tx\n .insert(ephemeralRegistrationTokens)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n reservationId: params.reservationId ?? null,\n providerRunnerId: params.providerRunnerId,\n hashedToken: params.hashedToken,\n prefix: params.prefix,\n expiresAt: params.expiresAt,\n })\n .returning();\n });\n\n const row = rows[0];\n if (!row) throw new Error('Insert returned no rows');\n return toEphemeralRegistrationToken(row);\n}\n\nexport async function createEphemeralRegistrationTokensBatch(\n params: CreateEphemeralRegistrationTokensBatchParams,\n): Promise<EphemeralRegistrationToken[]> {\n const rows = await db().transaction(async (tx) => {\n const provisionerLockKey = [\n 'runners_ephemeral_registration_tokens',\n params.workspaceId,\n params.provisionerId,\n ].join(':');\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${provisionerLockKey}))`);\n for (const providerRunnerId of [\n ...new Set(params.rows.map((row) => row.providerRunnerId)),\n ].sort()) {\n const providerRunnerLockKey = [\n 'runners_ephemeral_registration_tokens',\n params.workspaceId,\n params.provisionerId,\n providerRunnerId,\n ].join(':');\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${providerRunnerLockKey}))`);\n }\n\n const [reservation] = await tx\n .select({\n count: reservations.count,\n isExpired: sql<boolean>`${reservations.expiresAt} <= now()`,\n })\n .from(reservations)\n .where(\n and(\n eq(reservations.id, params.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.kind, 'launch'),\n ),\n )\n .limit(1);\n\n if (!reservation) throw new ReservationNotFoundError(params.reservationId);\n if (reservation.isExpired) throw new ReservationExpiredError(params.reservationId);\n if (params.rows.length > reservation.count) {\n throw new RegistrationTokenBatchExceedsReservationError(\n params.rows.length,\n reservation.count,\n );\n }\n\n const [existingForReservation] = await tx\n .select({count: sql<number>`count(*)::int`})\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n eq(ephemeralRegistrationTokens.reservationId, params.reservationId),\n ),\n );\n const alreadyMinted = existingForReservation?.count ?? 0;\n if (alreadyMinted + params.rows.length > reservation.count) {\n throw new RegistrationTokenBatchExceedsReservationError(\n params.rows.length,\n reservation.count,\n alreadyMinted,\n );\n }\n\n const providerRunnerIds = params.rows.map((row) => row.providerRunnerId);\n const activeRows = await tx\n .select({providerRunnerId: ephemeralRegistrationTokens.providerRunnerId})\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n inArray(ephemeralRegistrationTokens.providerRunnerId, providerRunnerIds),\n isNull(ephemeralRegistrationTokens.consumedAt),\n gt(ephemeralRegistrationTokens.expiresAt, sql`now()`),\n ),\n );\n\n if (activeRows.length > 0) {\n throw new ActiveEphemeralRegistrationTokensExistError(\n activeRows.map((row) => row.providerRunnerId),\n );\n }\n\n return await tx\n .insert(ephemeralRegistrationTokens)\n .values(\n params.rows.map((row) => ({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n reservationId: params.reservationId,\n providerRunnerId: row.providerRunnerId,\n hashedToken: row.hashedToken,\n prefix: row.prefix,\n expiresAt: params.expiresAt,\n })),\n )\n .returning();\n });\n\n return rows.map(toEphemeralRegistrationToken);\n}\n\nexport async function resolveEphemeralRegistrationTokenByHash(\n hashedToken: string,\n): Promise<EphemeralRegistrationToken | undefined> {\n const rows = await db()\n .select()\n .from(ephemeralRegistrationTokens)\n .where(eq(ephemeralRegistrationTokens.hashedToken, hashedToken))\n .limit(1);\n\n const row = rows[0];\n if (!row) return undefined;\n return toEphemeralRegistrationToken(row);\n}\n\nexport interface DeleteExpiredEphemeralRegistrationTokensParams {\n retentionDays: number;\n limit?: number;\n}\n\n/**\n * Deletes ephemeral registration tokens that have reached a terminal state and\n * outlived the retention window. A token is terminal once it is consumed\n * (single use spent) or expired without consumption; the retention window is\n * measured from that terminal event so the audit record survives a bounded\n * debugging window. Active tokens that are neither consumed nor expired are\n * never deleted, so a live single-use credential is never removed early.\n */\nexport async function deleteExpiredEphemeralRegistrationTokens(\n params: DeleteExpiredEphemeralRegistrationTokensParams,\n): Promise<number> {\n // coalesce(consumed_at, expires_at) is the terminal timestamp: consumed_at\n // when the token was spent, otherwise its expiry. Comparing it to the cutoff\n // both selects deletable rows and orders the batch, and it matches the\n // terminal index so idle GC ticks never scan live rows.\n const terminalAt = sql`coalesce(${ephemeralRegistrationTokens.consumedAt}, ${ephemeralRegistrationTokens.expiresAt})`;\n const retentionCutoff = sql`now() - (${params.retentionDays} || ' days')::interval`;\n\n const deletableIds = db()\n .select({id: ephemeralRegistrationTokens.id})\n .from(ephemeralRegistrationTokens)\n .where(lt(terminalAt, retentionCutoff))\n .orderBy(asc(terminalAt), asc(ephemeralRegistrationTokens.id))\n .limit(params.limit ?? 1000);\n\n const deleted = await db()\n .delete(ephemeralRegistrationTokens)\n .where(inArray(ephemeralRegistrationTokens.id, deletableIds))\n .returning({id: ephemeralRegistrationTokens.id});\n\n return deleted.length;\n}\n\nexport async function createRunnerSessionConsumingEphemeralToken(params: {\n ephemeralTokenId: string;\n workspaceId: string;\n labels: string[];\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n maxClaims: number;\n}) {\n return await db().transaction(async (tx) => {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);\n\n const consumed = await tx\n .update(ephemeralRegistrationTokens)\n .set({consumedAt: sql`now()`})\n .where(\n and(\n eq(ephemeralRegistrationTokens.id, params.ephemeralTokenId),\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n isNull(ephemeralRegistrationTokens.consumedAt),\n gt(ephemeralRegistrationTokens.expiresAt, sql`now()`),\n ),\n )\n .returning({\n id: ephemeralRegistrationTokens.id,\n provisionerId: ephemeralRegistrationTokens.provisionerId,\n providerRunnerId: ephemeralRegistrationTokens.providerRunnerId,\n });\n\n if (!consumed[0]) {\n const [token] = await tx\n .select({\n workspaceId: ephemeralRegistrationTokens.workspaceId,\n consumedAt: ephemeralRegistrationTokens.consumedAt,\n isExpired: sql<boolean>`${ephemeralRegistrationTokens.expiresAt} <= now()`,\n })\n .from(ephemeralRegistrationTokens)\n .where(eq(ephemeralRegistrationTokens.id, params.ephemeralTokenId))\n .limit(1);\n\n if (!token) {\n throw new Error(`Ephemeral registration token not found: ${params.ephemeralTokenId}`);\n }\n if (token.workspaceId !== params.workspaceId) {\n throw new RegistrationTokenWorkspaceMismatchError(\n params.ephemeralTokenId,\n params.workspaceId,\n );\n }\n if (token.consumedAt) throw new RegistrationTokenConsumedError(params.ephemeralTokenId);\n if (token.isExpired) throw new RegistrationTokenExpiredError(params.ephemeralTokenId);\n throw new Error(\n `Ephemeral registration token could not be consumed: ${params.ephemeralTokenId}`,\n );\n }\n\n const [provisioner] = await tx\n .select({scope: provisionerTokens.scope})\n .from(provisionerTokens)\n .where(eq(provisionerTokens.id, consumed[0].provisionerId))\n .limit(1);\n const labels = sanitizeRunnerLabelsOrThrow(params.labels, {\n scope: provisioner?.scope ?? 'workspace',\n source: 'ephemeral runner registration',\n });\n if (labels.length === 0) throw new EmptyRunnerLabelsError();\n\n const [session] = await tx\n .insert(runnerSessions)\n .values({\n workspaceId: params.workspaceId,\n scope: 'workspace',\n registrationTokenId: params.ephemeralTokenId,\n registrationTokenKind: 'ephemeral',\n provisionerId: consumed[0].provisionerId,\n providerRunnerId: consumed[0].providerRunnerId,\n labels,\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n maxClaims: params.maxClaims,\n claimsUsed: 0,\n })\n .returning();\n\n if (!session) throw new Error('Insert returned no rows');\n\n await tx\n .update(ephemeralRegistrationTokens)\n .set({consumedSessionId: session.id})\n .where(eq(ephemeralRegistrationTokens.id, params.ephemeralTokenId));\n\n await tx\n .update(providerRunners)\n .set({runnerSessionId: session.id, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, consumed[0].provisionerId),\n eq(providerRunners.providerRunnerId, consumed[0].providerRunnerId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n\n return toRunnerSession(session);\n });\n}\n"],"names":["and","asc","eq","gt","inArray","isNull","lt","sql","ActiveEphemeralRegistrationTokenExistsError","ActiveEphemeralRegistrationTokensExistError","EmptyRunnerLabelsError","RegistrationTokenBatchExceedsReservationError","RegistrationTokenConsumedError","RegistrationTokenExpiredError","RegistrationTokenWorkspaceMismatchError","ReservationExpiredError","ReservationNotFoundError","sanitizeRunnerLabelsOrThrow","db","ephemeralRegistrationTokens","toEphemeralRegistrationToken","provisionerTokens","reservations","providerRunners","runnerSessions","toRunnerSession","createEphemeralRegistrationToken","params","rows","transaction","tx","providerRunnerLockKey","workspaceId","provisionerId","providerRunnerId","join","execute","active","select","id","from","where","consumedAt","expiresAt","limit","insert","values","reservationId","hashedToken","prefix","returning","row","Error","createEphemeralRegistrationTokensBatch","provisionerLockKey","Set","map","sort","reservation","count","isExpired","kind","length","existingForReservation","alreadyMinted","providerRunnerIds","activeRows","resolveEphemeralRegistrationTokenByHash","undefined","deleteExpiredEphemeralRegistrationTokens","terminalAt","retentionCutoff","retentionDays","deletableIds","orderBy","deleted","delete","createRunnerSessionConsumingEphemeralToken","consumed","update","set","ephemeralTokenId","token","provisioner","scope","labels","source","session","registrationTokenId","registrationTokenKind","toolCapabilities","toolCapabilitiesReportedAt","maxClaims","claimsUsed","consumedSessionId","runnerSessionId","updatedAt","reservationReleasedAt"],"mappings":"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"}
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { writeOutboxEvent, writeOutboxEvents } from '@shipfox/node-outbox';
|
|
|
4
4
|
import { canonicalizeLabels } from '@shipfox/runner-labels';
|
|
5
5
|
import { and, arrayContained, asc, count, desc, eq, gt, inArray, isNotNull, isNull, lt, lte, or, sql } from 'drizzle-orm';
|
|
6
6
|
import { EmptyRequiredLabelsError, RunnerSessionExhaustedError, RunningJobExecutionNotFoundError } from '#core/errors.js';
|
|
7
|
-
import { jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount } from '#metrics/instance.js';
|
|
7
|
+
import { jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, recordJobExecutionQueueTime, recordProviderRunnerActivationToFirstClaim } from '#metrics/instance.js';
|
|
8
8
|
import { db } from './db.js';
|
|
9
9
|
import { runnersOutbox } from './schema/outbox.js';
|
|
10
10
|
import { pendingJobExecutions } from './schema/pending-job-executions.js';
|
|
@@ -94,7 +94,9 @@ export async function claimPendingJobExecution(params) {
|
|
|
94
94
|
throttleSeconds: params.runnerSessionLivenessThrottleSeconds
|
|
95
95
|
});
|
|
96
96
|
if (params.sessionLabels.length === 0) return null;
|
|
97
|
-
|
|
97
|
+
let activationToFirstClaimObservation = null;
|
|
98
|
+
let queueTimeObservation = null;
|
|
99
|
+
const result = await db().transaction(async (tx)=>{
|
|
98
100
|
let provisionerId = null;
|
|
99
101
|
let providerRunnerId = null;
|
|
100
102
|
let runnerInstanceId = null;
|
|
@@ -155,12 +157,38 @@ export async function claimPendingJobExecution(params) {
|
|
|
155
157
|
});
|
|
156
158
|
const claimed = inserted[0];
|
|
157
159
|
if (!claimed) return null;
|
|
160
|
+
queueTimeObservation = {
|
|
161
|
+
durationMilliseconds: claimed.claimedAt.getTime() - row.createdAt.getTime(),
|
|
162
|
+
provider: null,
|
|
163
|
+
launchKind: params.maxClaims === null ? 'manual' : 'unknown'
|
|
164
|
+
};
|
|
158
165
|
const runnerInstanceCondition = runnerInstanceId ? eq(providerRunners.id, runnerInstanceId) : provisionerId && providerRunnerId ? and(eq(providerRunners.provisionerId, provisionerId), eq(providerRunners.providerRunnerId, providerRunnerId)) : null;
|
|
159
166
|
if (runnerInstanceCondition) {
|
|
160
|
-
await tx.update(providerRunners).set({
|
|
167
|
+
const [claimedRunner] = await tx.update(providerRunners).set({
|
|
161
168
|
firstClaimedAt: sql`coalesce(${providerRunners.firstClaimedAt}, ${claimed.claimedAt})`,
|
|
162
169
|
updatedAt: sql`now()`
|
|
163
|
-
}).where(runnerInstanceCondition)
|
|
170
|
+
}).where(runnerInstanceCondition).returning({
|
|
171
|
+
firstClaimedAt: providerRunners.firstClaimedAt,
|
|
172
|
+
isFirstClaim: sql`${providerRunners.firstClaimedAt} = ${claimed.claimedAt}`,
|
|
173
|
+
provider: providerRunners.providerKind,
|
|
174
|
+
launchKind: providerRunners.launchKind,
|
|
175
|
+
runnerInstanceId: providerRunners.id,
|
|
176
|
+
sessionCreatedAtEpochMs: sql`(
|
|
177
|
+
select extract(epoch from ${runnerSessions.createdAt})::double precision * 1000
|
|
178
|
+
from ${runnerSessions}
|
|
179
|
+
where ${runnerSessions.id} = ${params.runnerSessionId}
|
|
180
|
+
)`
|
|
181
|
+
});
|
|
182
|
+
if (claimedRunner && queueTimeObservation) {
|
|
183
|
+
queueTimeObservation.provider = claimedRunner.provider;
|
|
184
|
+
queueTimeObservation.launchKind = claimedRunner.launchKind;
|
|
185
|
+
}
|
|
186
|
+
if (claimedRunner?.isFirstClaim && claimedRunner.firstClaimedAt !== null && claimedRunner.sessionCreatedAtEpochMs !== null && claimedRunner.sessionCreatedAtEpochMs !== undefined) activationToFirstClaimObservation = {
|
|
187
|
+
durationMilliseconds: claimedRunner.firstClaimedAt.getTime() - claimedRunner.sessionCreatedAtEpochMs,
|
|
188
|
+
provider: claimedRunner.provider,
|
|
189
|
+
launchKind: claimedRunner.launchKind,
|
|
190
|
+
runnerInstanceId: claimedRunner.runnerInstanceId
|
|
191
|
+
};
|
|
164
192
|
}
|
|
165
193
|
if (params.maxClaims !== null) {
|
|
166
194
|
await tx.update(runnerSessions).set({
|
|
@@ -189,6 +217,9 @@ export async function claimPendingJobExecution(params) {
|
|
|
189
217
|
projectId: row.projectId
|
|
190
218
|
};
|
|
191
219
|
});
|
|
220
|
+
if (queueTimeObservation) recordJobExecutionQueueTime(queueTimeObservation);
|
|
221
|
+
if (activationToFirstClaimObservation) recordProviderRunnerActivationToFirstClaim(activationToFirstClaimObservation);
|
|
222
|
+
return result;
|
|
192
223
|
}
|
|
193
224
|
async function touchRunnerSessionLiveness(params) {
|
|
194
225
|
await db().update(runnerSessions).set({
|