@shipfox/api-runners 12.5.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 +15 -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/dist/db/reservations.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { canonicalizeLabels } from '@shipfox/runner-labels';
|
|
2
|
-
import { and, arrayContains, asc, eq, exists, gt, inArray, isNotNull, isNull, lt, notExists, notInArray, or, sql } from 'drizzle-orm';
|
|
2
|
+
import { and, arrayContains, asc, eq, exists, gt, inArray, isNotNull, isNull, lt, lte, notExists, notInArray, or, sql } from 'drizzle-orm';
|
|
3
3
|
import { recordProviderRunnerActivationOutcome } from '#metrics/instance.js';
|
|
4
4
|
import { db } from './db.js';
|
|
5
5
|
import { lockRunnerReservationAdvisoryKeysTx } from './reservation-locks.js';
|
|
@@ -11,6 +11,7 @@ import { reservations } from './schema/reservations.js';
|
|
|
11
11
|
import { runnerActivationTokens } from './schema/runner-activation-tokens.js';
|
|
12
12
|
import { runnerControlSessions } from './schema/runner-control-sessions.js';
|
|
13
13
|
import { providerRunners } from './schema/runner-instances.js';
|
|
14
|
+
import { runningJobExecutions } from './schema/running-job-executions.js';
|
|
14
15
|
export async function pollDemandAndReserve(params) {
|
|
15
16
|
const result = await db().transaction(async (tx)=>{
|
|
16
17
|
return await pollDemandAndReserveTx(tx, params);
|
|
@@ -238,9 +239,10 @@ async function listActiveProvisionerReservationRowsTx(tx, params) {
|
|
|
238
239
|
const usedRunnerRows = await tx.select({
|
|
239
240
|
id: providerRunners.id,
|
|
240
241
|
reservationId: providerRunners.reservationId,
|
|
241
|
-
intendedReservationId: providerRunners.intendedReservationId
|
|
242
|
-
|
|
243
|
-
|
|
242
|
+
intendedReservationId: providerRunners.intendedReservationId
|
|
243
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), isNull(providerRunners.reservationReleasedAt), or(and(inArray(providerRunners.reservationId, activeIds), notInArray(providerRunners.state, [
|
|
244
|
+
...terminalStates
|
|
245
|
+
])), and(inArray(providerRunners.intendedReservationId, activeIds), notInArray(providerRunners.state, [
|
|
244
246
|
...terminalStates
|
|
245
247
|
])))));
|
|
246
248
|
const usedByReservation = new Map();
|
|
@@ -248,7 +250,7 @@ async function listActiveProvisionerReservationRowsTx(tx, params) {
|
|
|
248
250
|
if (runner.reservationId && activeIdSet.has(runner.reservationId)) {
|
|
249
251
|
addUsedRunner(usedByReservation, runner.reservationId, runner.id);
|
|
250
252
|
}
|
|
251
|
-
if (runner.intendedReservationId && activeIdSet.has(runner.intendedReservationId)
|
|
253
|
+
if (runner.intendedReservationId && activeIdSet.has(runner.intendedReservationId)) {
|
|
252
254
|
addUsedRunner(usedByReservation, runner.intendedReservationId, runner.id);
|
|
253
255
|
}
|
|
254
256
|
}
|
|
@@ -457,22 +459,140 @@ async function deleteReservationsWithCleanupTx(tx, ids, params = {}) {
|
|
|
457
459
|
return deleted.length;
|
|
458
460
|
}
|
|
459
461
|
export async function releaseReservationUnits(tx, params) {
|
|
460
|
-
|
|
462
|
+
const releaseByReservationId = new Map();
|
|
461
463
|
for (const release of params.releases){
|
|
462
464
|
if (release.count <= 0) continue;
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
465
|
+
releaseByReservationId.set(release.reservationId, (releaseByReservationId.get(release.reservationId) ?? 0) + release.count);
|
|
466
|
+
}
|
|
467
|
+
const reservationIds = [
|
|
468
|
+
...releaseByReservationId.keys()
|
|
469
|
+
];
|
|
470
|
+
if (reservationIds.length === 0) return 0;
|
|
471
|
+
const releaseCount = sql`CASE ${reservations.id}
|
|
472
|
+
${sql.join([
|
|
473
|
+
...releaseByReservationId
|
|
474
|
+
].map(([reservationId, count])=>sql`WHEN ${reservationId} THEN ${count}`), sql` `)}
|
|
475
|
+
ELSE 0
|
|
476
|
+
END`;
|
|
477
|
+
const scope = and(eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId), inArray(reservations.id, reservationIds), gt(reservations.expiresAt, sql`now()`));
|
|
478
|
+
const decremented = await tx.update(reservations).set({
|
|
479
|
+
count: sql`${reservations.count} - ${releaseCount}`
|
|
480
|
+
}).where(and(scope, gt(reservations.count, releaseCount))).returning({
|
|
481
|
+
id: reservations.id
|
|
482
|
+
});
|
|
483
|
+
const releasedFromDecremented = decremented.reduce((total, row)=>total + (releaseByReservationId.get(row.id) ?? 0), 0);
|
|
484
|
+
const decrementedIds = decremented.map((row)=>row.id);
|
|
485
|
+
const deleted = await tx.delete(reservations).where(and(scope, sql`${reservations.count} <= ${releaseCount}`, decrementedIds.length > 0 ? notInArray(reservations.id, decrementedIds) : undefined)).returning({
|
|
486
|
+
count: reservations.count
|
|
487
|
+
});
|
|
488
|
+
const releasedFromDeleted = deleted.reduce((total, row)=>total + row.count, 0);
|
|
489
|
+
return releasedFromDeleted + releasedFromDecremented;
|
|
490
|
+
}
|
|
491
|
+
export async function releaseTerminalRunnerInstanceReservationsByIds(tx, params) {
|
|
492
|
+
if ((params.providerRunnerIds?.length ?? 0) === 0 && (params.runnerInstanceIds?.length ?? 0) === 0) return 0;
|
|
493
|
+
const reservationWorkspacePredicate = params.workspaceId === null ? sql`` : sql`and ${eq(reservations.workspaceId, params.workspaceId)}`;
|
|
494
|
+
const noRunningJobPredicate = notExists(tx.select({
|
|
495
|
+
id: runningJobExecutions.id
|
|
496
|
+
}).from(runningJobExecutions).where(and(eq(runningJobExecutions.provisionerId, params.provisionerId), eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId), params.workspaceId === null ? undefined : eq(runningJobExecutions.workspaceId, params.workspaceId))));
|
|
497
|
+
const reportFreshnessPredicate = params.reportedAtByProviderRunnerId && params.reportedAtByProviderRunnerId.size > 0 ? or(...[
|
|
498
|
+
...params.reportedAtByProviderRunnerId
|
|
499
|
+
].map(([providerRunnerId, reportedAt])=>and(eq(providerRunners.providerRunnerId, providerRunnerId), lte(providerRunners.reportedAt, reportedAt)))) : undefined;
|
|
500
|
+
const runnerIdentityPredicate = or(params.providerRunnerIds && params.providerRunnerIds.length > 0 ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds) : undefined, params.runnerInstanceIds && params.runnerInstanceIds.length > 0 ? inArray(providerRunners.id, params.runnerInstanceIds) : undefined);
|
|
501
|
+
// Assignment locks these keys before changing runner links. Acquire them before locking or
|
|
502
|
+
// marking terminal runners so an assignment cannot consume a reservation concurrently with
|
|
503
|
+
// this release.
|
|
504
|
+
const reservationRowsToLock = await tx.select({
|
|
505
|
+
reservationId: providerRunners.reservationId,
|
|
506
|
+
intendedReservationId: providerRunners.intendedReservationId
|
|
507
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), runnerIdentityPredicate, params.requireTerminalState === false ? undefined : inArray(providerRunners.state, terminalStates), or(isNotNull(providerRunners.reservationId), isNotNull(providerRunners.intendedReservationId)), isNull(providerRunners.reservationReleasedAt)));
|
|
508
|
+
const reservationIdsToLock = [
|
|
509
|
+
...new Set(reservationRowsToLock.flatMap((row)=>[
|
|
510
|
+
row.reservationId,
|
|
511
|
+
row.intendedReservationId
|
|
512
|
+
].filter((reservationId)=>reservationId !== null)))
|
|
513
|
+
];
|
|
514
|
+
await lockRunnerReservationAdvisoryKeysTx(tx, {
|
|
515
|
+
provisionerId: params.provisionerId,
|
|
516
|
+
reservationIds: reservationIdsToLock
|
|
517
|
+
});
|
|
518
|
+
const rows = await tx.select({
|
|
519
|
+
id: providerRunners.id,
|
|
520
|
+
state: providerRunners.state,
|
|
521
|
+
releaseReservationId: sql`coalesce(
|
|
522
|
+
(select ${reservations.id}
|
|
523
|
+
from ${reservations}
|
|
524
|
+
where ${reservations.id} = ${providerRunners.intendedReservationId}
|
|
525
|
+
and ${reservations.provisionerId} = ${params.provisionerId}
|
|
526
|
+
${reservationWorkspacePredicate}),
|
|
527
|
+
(select ${reservations.id}
|
|
528
|
+
from ${reservations}
|
|
529
|
+
where ${reservations.id} = ${providerRunners.reservationId}
|
|
530
|
+
and ${reservations.provisionerId} = ${params.provisionerId}
|
|
531
|
+
${reservationWorkspacePredicate})
|
|
532
|
+
)`,
|
|
533
|
+
releaseReservationWorkspaceId: sql`coalesce(
|
|
534
|
+
(select ${reservations.workspaceId}
|
|
535
|
+
from ${reservations}
|
|
536
|
+
where ${reservations.id} = ${providerRunners.intendedReservationId}
|
|
537
|
+
and ${reservations.provisionerId} = ${params.provisionerId}
|
|
538
|
+
${reservationWorkspacePredicate}),
|
|
539
|
+
(select ${reservations.workspaceId}
|
|
540
|
+
from ${reservations}
|
|
541
|
+
where ${reservations.id} = ${providerRunners.reservationId}
|
|
542
|
+
and ${reservations.provisionerId} = ${params.provisionerId}
|
|
543
|
+
${reservationWorkspacePredicate})
|
|
544
|
+
)`
|
|
545
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), runnerIdentityPredicate, params.requireTerminalState === false ? undefined : inArray(providerRunners.state, terminalStates), or(isNotNull(providerRunners.reservationId), isNotNull(providerRunners.intendedReservationId)), params.workspaceId === null ? undefined : or(and(eq(providerRunners.workspaceId, params.workspaceId), or(exists(tx.select({
|
|
546
|
+
id: reservations.id
|
|
547
|
+
}).from(reservations).where(and(eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId), eq(reservations.id, providerRunners.reservationId)))), exists(tx.select({
|
|
548
|
+
id: reservations.id
|
|
549
|
+
}).from(reservations).where(and(eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId), eq(reservations.id, providerRunners.intendedReservationId)))))), and(isNull(providerRunners.workspaceId), isNotNull(providerRunners.intendedReservationId), exists(tx.select({
|
|
550
|
+
id: reservations.id
|
|
551
|
+
}).from(reservations).where(and(eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId), eq(reservations.id, providerRunners.intendedReservationId)))))), params.requireUnlinkedSession === false ? undefined : isNull(providerRunners.runnerSessionId), noRunningJobPredicate, reportFreshnessPredicate, isNull(providerRunners.reservationReleasedAt))).for('update');
|
|
552
|
+
if (rows.length === 0) return 0;
|
|
553
|
+
// The lease-finalization path deliberately locks active rows too. If a terminal report is
|
|
554
|
+
// concurrently projecting the runner state, PostgreSQL rechecks this row after the lock and
|
|
555
|
+
// lets cleanup observe the committed terminal state without a cross-module advisory lock.
|
|
556
|
+
const terminalRows = params.requireTerminalState === false ? rows.filter((row)=>terminalStates.some((terminalState)=>terminalState === row.state)) : rows;
|
|
557
|
+
if (terminalRows.length === 0) return 0;
|
|
558
|
+
const updated = await tx.update(providerRunners).set({
|
|
559
|
+
intendedReservationId: null,
|
|
560
|
+
reservationReleasedAt: sql`now()`,
|
|
561
|
+
updatedAt: sql`now()`
|
|
562
|
+
}).where(and(inArray(providerRunners.id, terminalRows.map((row)=>row.id)), params.requireUnlinkedSession === false ? undefined : isNull(providerRunners.runnerSessionId), noRunningJobPredicate, reportFreshnessPredicate, isNull(providerRunners.reservationReleasedAt))).returning({
|
|
563
|
+
id: providerRunners.id
|
|
564
|
+
});
|
|
565
|
+
const releasesByReservationId = new Map();
|
|
566
|
+
const updatedIds = new Set(updated.map((row)=>row.id));
|
|
567
|
+
for (const row of terminalRows){
|
|
568
|
+
if (!updatedIds.has(row.id)) continue;
|
|
569
|
+
if (!row.releaseReservationId || !row.releaseReservationWorkspaceId) continue;
|
|
570
|
+
const key = `${row.releaseReservationWorkspaceId}:${row.releaseReservationId}`;
|
|
571
|
+
const release = releasesByReservationId.get(key) ?? {
|
|
572
|
+
workspaceId: row.releaseReservationWorkspaceId,
|
|
573
|
+
reservationId: row.releaseReservationId,
|
|
574
|
+
count: 0
|
|
575
|
+
};
|
|
576
|
+
release.count += 1;
|
|
577
|
+
releasesByReservationId.set(key, release);
|
|
578
|
+
}
|
|
579
|
+
if (releasesByReservationId.size === 0) return 0;
|
|
580
|
+
const releasesByWorkspaceId = new Map();
|
|
581
|
+
for (const release of releasesByReservationId.values()){
|
|
582
|
+
const releases = releasesByWorkspaceId.get(release.workspaceId) ?? [];
|
|
583
|
+
releases.push({
|
|
584
|
+
reservationId: release.reservationId,
|
|
585
|
+
count: release.count
|
|
467
586
|
});
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
587
|
+
releasesByWorkspaceId.set(release.workspaceId, releases);
|
|
588
|
+
}
|
|
589
|
+
let released = 0;
|
|
590
|
+
for (const [workspaceId, releases] of releasesByWorkspaceId){
|
|
591
|
+
released += await releaseReservationUnits(tx, {
|
|
592
|
+
workspaceId,
|
|
593
|
+
provisionerId: params.provisionerId,
|
|
594
|
+
releases
|
|
474
595
|
});
|
|
475
|
-
released += deleted.reduce((total, row)=>total + row.count, 0);
|
|
476
596
|
}
|
|
477
597
|
return released;
|
|
478
598
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/reservations.ts"],"sourcesContent":["import {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContains,\n asc,\n eq,\n exists,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n notExists,\n notInArray,\n or,\n sql,\n} from 'drizzle-orm';\nimport {recordProviderRunnerActivationOutcome} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {lockRunnerReservationAdvisoryKeysTx} from './reservation-locks.js';\nimport {terminalStates} from './runner-states.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {provisionerCapabilitySnapshots} from './schema/provisioner-capability-snapshots.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\nimport {runnerActivationTokens} from './schema/runner-activation-tokens.js';\nimport {runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {type providerRunnerLaunchKindEnum, providerRunners} from './schema/runner-instances.js';\n\nexport interface ReservationTemplate {\n templateKey: string;\n labels: string[];\n availableSlots: number;\n starting: number;\n running: number;\n}\n\nexport interface DemandStat {\n workspaceId?: string;\n labels: string[];\n queued: number;\n reserved: number;\n oldestQueuedAt: Date;\n}\n\nexport interface ReservationGrant {\n reservationId: string;\n workspaceId?: string;\n labels: string[];\n count: number;\n expiresAt: Date;\n}\n\nexport interface PollDemandAndReserveParams {\n workspaceId: string;\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n /** Lifetime of the short reservation that gives rebound runners time to activate. */\n activationGraceSeconds?: number;\n templates: ReservationTemplate[];\n capabilityWindowSeconds?: number;\n}\n\nexport interface InstallationPollDemandAndReserveParams {\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n /** Lifetime of the short reservation that gives rebound runners time to activate. */\n activationGraceSeconds?: number;\n templates: ReservationTemplate[];\n capabilityWindowSeconds: number;\n eligibleWorkspaceIds: ReadonlySet<string>;\n signal?: AbortSignal;\n onReservations?: (reservations: ReservationGrant[]) => void;\n}\n\ntype DemandScope = 'installation' | 'workspace';\n\ninterface IdleRunnerCandidate {\n id: string;\n launchKind: (typeof providerRunnerLaunchKindEnum.enumValues)[number];\n}\n\ninterface BindableRunnerParams {\n provisionerId: string;\n workspaceId: string;\n requiredLabels: string[];\n scope: DemandScope;\n}\n\ninterface IdleRunnerSelectionParams extends BindableRunnerParams {\n count: number;\n}\n\ntype PollDemandAndReserveLockedParams = PollDemandAndReserveParams & {\n scope: DemandScope;\n};\n\ninterface NormalizedTemplate {\n templateKey: string;\n labels: string[];\n remainingSlots: number;\n}\n\ninterface DemandRow {\n requiredLabels: string[];\n queued: number;\n oldestQueuedAt: Date;\n}\n\ninterface NewReservationUnits {\n labels: string[];\n count: number;\n}\n\ninterface PollDemandAndReserveResult {\n stats: DemandStat[];\n /** Only launch reservations are exposed to the provisioner. */\n reservations: ReservationGrant[];\n /** Internal allocation accounting for bound and launch rows together. */\n newlyReservedUnits: NewReservationUnits[];\n}\n\nexport async function pollDemandAndReserve(\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n const result = await db().transaction(async (tx) => {\n return await pollDemandAndReserveTx(tx, params);\n });\n return {stats: result.stats, reservations: result.reservations};\n}\n\nexport async function pollDemandAndReserveTx(\n tx: Tx,\n params: PollDemandAndReserveParams,\n): Promise<PollDemandAndReserveResult> {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);\n return await pollDemandAndReserveLockedTx(tx, {...params, scope: 'workspace'});\n}\n\nexport async function pollInstallationDemandAndReserve(\n params: InstallationPollDemandAndReserveParams,\n): Promise<{\n stats: DemandStat[];\n reservations: ReservationGrant[];\n newlyReservedCount?: number;\n}> {\n const candidateWorkspaceIds = await listInstallationDemandWorkspaceIds(\n params.eligibleWorkspaceIds,\n );\n const results: PollDemandAndReserveResult[] = [];\n let remainingMaxReservations = params.maxReservations;\n const remainingTemplates = params.templates.map((template) => ({\n ...template,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n for (const workspaceId of candidateWorkspaceIds) {\n if (params.signal?.aborted || remainingMaxReservations === 0) break;\n const result = await db().transaction(async (tx) => {\n const lockResult = await tx.execute<{locked: boolean}>(\n sql`select pg_try_advisory_xact_lock(hashtext(${workspaceId})) as locked`,\n );\n const locked = lockResult.rows[0];\n if (!locked?.locked) return {stats: [], reservations: [], newlyReservedUnits: []};\n return await pollDemandAndReserveLockedTx(tx, {\n workspaceId,\n provisionerId: params.provisionerId,\n maxReservations: remainingMaxReservations,\n ttlSeconds: params.ttlSeconds,\n ...(params.activationGraceSeconds !== undefined\n ? {activationGraceSeconds: params.activationGraceSeconds}\n : {}),\n templates: remainingTemplates.map((template) => ({\n ...template,\n availableSlots: template.remainingSlots,\n })),\n capabilityWindowSeconds: params.capabilityWindowSeconds,\n scope: 'installation',\n });\n });\n results.push(result);\n consumeInstallationTemplateSlots(remainingTemplates, result.reservations);\n params.onReservations?.(result.reservations);\n remainingMaxReservations -= result.newlyReservedUnits.reduce(\n (total, reservation) => total + reservation.count,\n 0,\n );\n }\n const newlyReservedCount = results.reduce(\n (total, result) =>\n total +\n result.newlyReservedUnits.reduce((subtotal, reservation) => subtotal + reservation.count, 0),\n 0,\n );\n return {\n stats: results.flatMap((result) => result.stats),\n reservations: results.flatMap((result) => result.reservations),\n ...(newlyReservedCount > 0 ? {newlyReservedCount} : {}),\n };\n}\n\nfunction consumeInstallationTemplateSlots(\n templates: NormalizedTemplate[],\n launchGrants: ReservationGrant[],\n): void {\n // Adopted runners are already included in the running count behind availableSlots.\n // Only units that still need a launch consume advertised template capacity.\n for (const reservation of launchGrants) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.labels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.count);\n }\n}\n\nasync function pollDemandAndReserveLockedTx(\n tx: Tx,\n params: PollDemandAndReserveLockedParams,\n): Promise<PollDemandAndReserveResult> {\n let demandRows = (\n await tx\n .select({\n requiredLabels: pendingJobExecutions.requiredLabels,\n queued: sql<number>`count(*)::int`,\n oldestQueuedAt: sql<Date | string>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(eq(pendingJobExecutions.workspaceId, params.workspaceId))\n .groupBy(pendingJobExecutions.requiredLabels)\n ).map((row) => ({\n ...row,\n oldestQueuedAt: new Date(row.oldestQueuedAt),\n }));\n if (params.capabilityWindowSeconds !== undefined) {\n const capabilityLabels = await listActiveWorkspaceCapabilityLabelsTx(tx, {\n workspaceId: params.workspaceId,\n windowSeconds: params.capabilityWindowSeconds,\n });\n demandRows = demandRows.filter(\n (demand) => !capabilityLabels.some((labels) => isSubset(demand.requiredLabels, labels)),\n );\n }\n\n const activeReservationRows = await tx\n .select({\n requiredLabels: reservations.requiredLabels,\n reserved: sql<number>`coalesce(sum(${reservations.count}), 0)::int`,\n })\n .from(reservations)\n .where(\n and(eq(reservations.workspaceId, params.workspaceId), gt(reservations.expiresAt, sql`now()`)),\n )\n .groupBy(reservations.requiredLabels);\n\n const reservedByLabels = new Map(\n activeReservationRows.map((row) => [labelKey(row.requiredLabels), row.reserved]),\n );\n const activeProvisionerReservationRows = await listActiveProvisionerReservationRowsTx(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n });\n\n const templates = params.templates.map((template) => ({\n templateKey: template.templateKey,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n deductProvisionerReservations(templates, activeProvisionerReservationRows);\n const stats: DemandStat[] = [];\n const grants: ReservationGrant[] = [];\n const newlyReservedUnits: NewReservationUnits[] = [];\n let remainingMaxReservations = params.maxReservations;\n const workspaceIdField =\n params.capabilityWindowSeconds === undefined ? {} : {workspaceId: params.workspaceId};\n\n for (const demand of sortDemandRows(demandRows)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(demand.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n\n if (satisfyingTemplates.length === 0) continue;\n\n const reserved = reservedByLabels.get(labelKey(demand.requiredLabels)) ?? 0;\n const unreserved = Math.max(0, demand.queued - reserved);\n const capacity = satisfyingTemplates.reduce(\n (total, template) => total + template.remainingSlots,\n 0,\n );\n const grant = Math.min(unreserved, capacity, remainingMaxReservations);\n let reservedAfterGrant = reserved;\n\n if (grant > 0 && params.maxReservations > 0) {\n const idleRunners = await listIdleRunnerInstancesTx(tx, {\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: grant,\n workspaceId: params.workspaceId,\n scope: params.scope,\n });\n\n remainingMaxReservations -= grant;\n\n const boundCount = idleRunners.length;\n if (boundCount > 0) {\n const [boundReservation] = await tx\n .insert(reservations)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: boundCount,\n kind: 'bound',\n expiresAt: sql`now() + (${params.activationGraceSeconds ?? params.ttlSeconds} || ' seconds')::interval`,\n })\n .returning({id: reservations.id});\n\n if (!boundReservation) throw new Error('Insert returned no rows');\n\n await bindIdleRunnerInstancesTx(tx, {\n provisionerId: params.provisionerId,\n reservationId: boundReservation.id,\n workspaceId: params.workspaceId,\n requiredLabels: demand.requiredLabels,\n scope: params.scope,\n idleRunners,\n });\n }\n\n const launchCount = grant - boundCount;\n drawSlots(satisfyingTemplates, launchCount);\n let launchReservation: {id: string; expiresAt: Date} | undefined;\n if (launchCount > 0) {\n const [inserted] = await tx\n .insert(reservations)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: launchCount,\n kind: 'launch',\n expiresAt: sql`now() + (${params.ttlSeconds} || ' seconds')::interval`,\n })\n .returning({id: reservations.id, expiresAt: reservations.expiresAt});\n\n if (!inserted) throw new Error('Insert returned no rows');\n launchReservation = inserted;\n }\n\n newlyReservedUnits.push({labels: demand.requiredLabels, count: grant});\n reservedAfterGrant += grant;\n if (launchReservation) {\n grants.push({\n reservationId: launchReservation.id,\n ...workspaceIdField,\n labels: demand.requiredLabels,\n count: launchCount,\n expiresAt: launchReservation.expiresAt,\n });\n }\n }\n\n stats.push({\n ...workspaceIdField,\n labels: demand.requiredLabels,\n queued: demand.queued,\n reserved: reservedAfterGrant,\n oldestQueuedAt: demand.oldestQueuedAt,\n });\n }\n\n return {stats, reservations: grants, newlyReservedUnits};\n}\n\nasync function listActiveProvisionerReservationRowsTx(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string},\n): Promise<Array<{requiredLabels: string[]; reserved: number}>> {\n const candidateRows = await tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n );\n const candidateIds = candidateRows.map((row) => row.id);\n if (candidateIds.length === 0) return [];\n\n // Assignment and provider-report transactions use this key before changing runner\n // links. Lock it before counting so an in-flight assignment cannot expose its unit twice.\n await lockRunnerReservationAdvisoryKeysTx(tx, {\n provisionerId: params.provisionerId,\n reservationIds: candidateIds,\n });\n\n const activeRows = await tx\n .select({\n id: reservations.id,\n requiredLabels: reservations.requiredLabels,\n count: reservations.count,\n })\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .orderBy(asc(reservations.id))\n .for('update');\n if (activeRows.length === 0) return [];\n\n const activeIds = activeRows.map((row) => row.id);\n const activeIdSet = new Set(activeIds);\n const usedRunnerRows = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n state: providerRunners.state,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.reservationReleasedAt),\n or(\n inArray(providerRunners.reservationId, activeIds),\n and(\n inArray(providerRunners.intendedReservationId, activeIds),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n ),\n ),\n );\n const usedByReservation = new Map<string, Set<string>>();\n for (const runner of usedRunnerRows) {\n if (runner.reservationId && activeIdSet.has(runner.reservationId)) {\n addUsedRunner(usedByReservation, runner.reservationId, runner.id);\n }\n if (\n runner.intendedReservationId &&\n activeIdSet.has(runner.intendedReservationId) &&\n !terminalStates.includes(runner.state as (typeof terminalStates)[number])\n ) {\n addUsedRunner(usedByReservation, runner.intendedReservationId, runner.id);\n }\n }\n\n return activeRows.flatMap((reservation) => {\n const used = usedByReservation.get(reservation.id)?.size ?? 0;\n const pending = Math.max(0, reservation.count - used);\n return pending > 0 ? [{requiredLabels: reservation.requiredLabels, reserved: pending}] : [];\n });\n}\n\nfunction addUsedRunner(\n usedByReservation: Map<string, Set<string>>,\n reservationId: string,\n runnerId: string,\n): void {\n const runnerIds = usedByReservation.get(reservationId);\n if (runnerIds) runnerIds.add(runnerId);\n else usedByReservation.set(reservationId, new Set([runnerId]));\n}\n\n// An expired or missing reservation is stale. A live reservation protects a runner that is\n// still booting or waiting for its activation grace period.\nfunction canBindRunner(tx: Tx, params: BindableRunnerParams) {\n return and(\n or(\n and(isNull(providerRunners.workspaceId), isNull(providerRunners.reservationId)),\n and(\n isNotNull(providerRunners.reservationId),\n params.scope === 'installation'\n ? undefined\n : or(\n isNull(providerRunners.workspaceId),\n eq(providerRunners.workspaceId, params.workspaceId),\n ),\n notExists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.id, providerRunners.reservationId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n ),\n ),\n ),\n ),\n or(\n isNull(providerRunners.intendedReservationId),\n notExists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.id, providerRunners.intendedReservationId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n ),\n ),\n ),\n isNull(providerRunners.reservationReleasedAt),\n isNull(providerRunners.runnerSessionId),\n );\n}\n\nfunction isBindableRunner(tx: Tx, params: BindableRunnerParams) {\n return and(\n eq(providerRunners.provisionerId, params.provisionerId),\n canBindRunner(tx, params),\n isNotNull(providerRunners.providerRunnerId),\n eq(providerRunners.state, 'running'),\n arrayContains(providerRunners.labels, params.requiredLabels),\n exists(\n tx\n .select({id: runnerControlSessions.id})\n .from(runnerControlSessions)\n .where(\n and(\n eq(runnerControlSessions.runnerInstanceId, providerRunners.id),\n eq(runnerControlSessions.provisionerId, params.provisionerId),\n isNull(runnerControlSessions.closedAt),\n gt(runnerControlSessions.expiresAt, sql`now()`),\n ),\n ),\n ),\n );\n}\n\nasync function listIdleRunnerInstancesTx(\n tx: Tx,\n params: IdleRunnerSelectionParams & {count: number},\n): Promise<IdleRunnerCandidate[]> {\n const lockedRunners = await selectIdleRunnerInstancesTx(tx, params);\n if (lockedRunners.length === 0) return lockedRunners;\n\n // A SELECT ... FOR UPDATE can wake with a fresh target row but the original\n // statement snapshot for reservation subqueries. Re-check the full predicate\n // in a new statement while retaining the row locks from the first query.\n return await selectIdleRunnerInstancesTx(tx, {\n ...params,\n runnerIds: lockedRunners.map((runner) => runner.id),\n count: lockedRunners.length,\n });\n}\n\nasync function selectIdleRunnerInstancesTx(\n tx: Tx,\n params: IdleRunnerSelectionParams & {count: number; runnerIds?: string[]},\n): Promise<IdleRunnerCandidate[]> {\n if (params.runnerIds) {\n // The first pass retains the row locks. Recheck the full predicate in a fresh statement so\n // reservation subqueries see the state that was current when the lock was acquired.\n return await tx\n .select({id: providerRunners.id, launchKind: providerRunners.launchKind})\n .from(providerRunners)\n .where(and(inArray(providerRunners.id, params.runnerIds), isBindableRunner(tx, params)))\n .orderBy(asc(providerRunners.createdAt), asc(providerRunners.id))\n .limit(params.count);\n }\n\n // Select the oldest candidates first, but leave row locking to a second pass. The cleanup\n // path locks runner rows by id, so the locking pass must use that same order. A skipped row\n // rolls back only this nested savepoint and retries the bounded candidate scan, allowing the\n // next-oldest eligible runner to refill the grant without retaining a partial lock set.\n const retrySelection = Symbol('retry bindable runner selection');\n const idleRunners = await (async () => {\n while (true) {\n try {\n return await tx.transaction(async (lockTx) => {\n const candidateRunners = await lockTx\n .select({id: providerRunners.id, launchKind: providerRunners.launchKind})\n .from(providerRunners)\n .where(isBindableRunner(lockTx, params))\n .orderBy(asc(providerRunners.createdAt), asc(providerRunners.id))\n .limit(params.count);\n\n if (candidateRunners.length === 0) return candidateRunners;\n\n // PostgreSQL can acquire row locks before sorting a multi-row FOR UPDATE result. Lock\n // each selected candidate individually so both polling and cleanup use id order.\n const lockedRunners: typeof candidateRunners = [];\n for (const candidate of [...candidateRunners].sort(compareRunnerIds)) {\n const [runner] = await lockTx\n .select({id: providerRunners.id, launchKind: providerRunners.launchKind})\n .from(providerRunners)\n .where(and(eq(providerRunners.id, candidate.id), isBindableRunner(lockTx, params)))\n .for('update');\n if (runner) lockedRunners.push(runner);\n }\n\n if (lockedRunners.length !== candidateRunners.length) throw retrySelection;\n return lockedRunners;\n });\n } catch (error) {\n if (error !== retrySelection) throw error;\n }\n }\n })();\n\n return idleRunners;\n}\n\nasync function bindIdleRunnerInstancesTx(\n tx: Tx,\n params: {\n provisionerId: string;\n reservationId: string;\n workspaceId: string;\n requiredLabels: string[];\n scope: DemandScope;\n idleRunners: IdleRunnerCandidate[];\n },\n): Promise<void> {\n const idleRunnerIds = params.idleRunners.map((runner) => runner.id);\n\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n inArray(runnerActivationTokens.runnerInstanceId, idleRunnerIds),\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n ),\n );\n\n // listIdleRunnerInstancesTx re-checks the full eligibility predicate in a fresh statement\n // after acquiring row locks. Those locks prevent the validated set from changing before this\n // update runs.\n const boundRunners = await tx\n .update(providerRunners)\n .set({\n workspaceId: params.workspaceId,\n reservationId: params.reservationId,\n intendedReservationId: null,\n assignedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(and(inArray(providerRunners.id, idleRunnerIds), isBindableRunner(tx, params)))\n .returning({id: providerRunners.id, launchKind: providerRunners.launchKind});\n\n if (boundRunners.length !== params.idleRunners.length)\n throw new Error('Locked idle runner set changed before binding');\n\n const reboundCount = boundRunners.filter((runner) => runner.launchKind === 'demand').length;\n if (reboundCount > 0)\n recordProviderRunnerActivationOutcome({outcome: 'rebound', count: reboundCount});\n}\n\nasync function listInstallationDemandWorkspaceIds(eligibleWorkspaceIds: ReadonlySet<string>) {\n if (eligibleWorkspaceIds.size === 0) return [];\n const rows = await db()\n .select({\n workspaceId: pendingJobExecutions.workspaceId,\n oldestQueuedAt: sql<Date>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.workspaceId, [...eligibleWorkspaceIds]))\n .groupBy(pendingJobExecutions.workspaceId)\n .orderBy(\n asc(sql`min(${pendingJobExecutions.createdAt})`),\n asc(pendingJobExecutions.workspaceId),\n );\n return rows.map((row) => row.workspaceId);\n}\n\nexport async function listQueuedDemandWorkspaceIds(): Promise<string[]> {\n const rows = await db()\n .select({workspaceId: pendingJobExecutions.workspaceId})\n .from(pendingJobExecutions)\n .groupBy(pendingJobExecutions.workspaceId);\n return rows.map((row) => row.workspaceId);\n}\n\nasync function listActiveWorkspaceCapabilityLabelsTx(\n tx: Tx,\n params: {workspaceId: string; windowSeconds: number},\n): Promise<string[][]> {\n const rows = await tx\n .select({labels: provisionerCapabilitySnapshots.labels})\n .from(provisionerCapabilitySnapshots)\n .innerJoin(\n provisionerTokens,\n eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId),\n )\n .where(\n and(\n eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n sql`${provisionerCapabilitySnapshots.advertisedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n sql`${provisionerTokens.revokedAt} is null`,\n sql`(${provisionerTokens.expiresAt} is null or ${provisionerTokens.expiresAt} > now())`,\n ),\n );\n return rows.map((row) => row.labels);\n}\n\nexport async function deleteExpiredReservations(params?: {limit?: number}): Promise<number> {\n return await db().transaction(async (tx) => {\n const expiredRows = await tx\n .select({id: reservations.id})\n .from(reservations)\n .where(lt(reservations.expiresAt, sql`now()`))\n .orderBy(asc(reservations.expiresAt))\n .limit(params?.limit ?? 1000);\n return await deleteReservationsWithCleanupTx(\n tx,\n expiredRows.map((reservation) => reservation.id),\n {expiredOnly: true},\n );\n });\n}\n\nexport async function deleteReservationsByIds(ids: string[]): Promise<number> {\n if (ids.length === 0) return 0;\n\n return await db().transaction(async (tx) => {\n return await deleteReservationsWithCleanupTx(tx, ids);\n });\n}\n\nasync function deleteReservationsWithCleanupTx(\n tx: Tx,\n ids: string[],\n params: {expiredOnly?: boolean} = {},\n): Promise<number> {\n if (ids.length === 0) return 0;\n\n const isAffectedRunner = () =>\n or(\n and(\n inArray(providerRunners.reservationId, ids),\n isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n inArray(providerRunners.intendedReservationId, ids),\n );\n const candidateRunners = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n runnerSessionId: providerRunners.runnerSessionId,\n reservationReleasedAt: providerRunners.reservationReleasedAt,\n })\n .from(providerRunners)\n .where(isAffectedRunner())\n .orderBy(asc(providerRunners.id));\n const affectedRunners: typeof candidateRunners = [];\n for (const candidate of [...candidateRunners].sort(compareRunnerIds)) {\n const [runner] = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n runnerSessionId: providerRunners.runnerSessionId,\n reservationReleasedAt: providerRunners.reservationReleasedAt,\n })\n .from(providerRunners)\n .where(and(eq(providerRunners.id, candidate.id), isAffectedRunner()))\n .for('update');\n if (runner) affectedRunners.push(runner);\n }\n const reservationRows = await tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n inArray(reservations.id, ids),\n params.expiredOnly ? lt(reservations.expiresAt, sql`now()`) : undefined,\n ),\n )\n .for('update');\n const reservationIds = reservationRows.map((reservation) => reservation.id);\n\n if (reservationIds.length === 0) return 0;\n\n const assignedRunnerIds = affectedRunners\n .filter(\n (runner) =>\n runner.reservationId &&\n reservationIds.includes(runner.reservationId) &&\n !runner.runnerSessionId &&\n !runner.reservationReleasedAt,\n )\n .map((runner) => runner.id);\n const intendedRunnerIds = affectedRunners\n .filter(\n (runner) =>\n runner.intendedReservationId && reservationIds.includes(runner.intendedReservationId),\n )\n .map((runner) => runner.id);\n if (assignedRunnerIds.length > 0) {\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n inArray(runnerActivationTokens.runnerInstanceId, assignedRunnerIds),\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n ),\n );\n await tx\n .update(providerRunners)\n .set({\n workspaceId: null,\n reservationId: null,\n assignedAt: null,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(providerRunners.id, assignedRunnerIds),\n isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n }\n if (intendedRunnerIds.length > 0) {\n await tx\n .update(providerRunners)\n .set({intendedReservationId: null, updatedAt: sql`now()`})\n .where(\n and(\n inArray(providerRunners.id, intendedRunnerIds),\n inArray(providerRunners.intendedReservationId, reservationIds),\n ),\n );\n }\n\n const deleted = await tx\n .delete(reservations)\n .where(inArray(reservations.id, reservationIds))\n .returning({id: reservations.id});\n\n return deleted.length;\n}\n\nexport async function releaseReservationUnits(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n releases: Array<{reservationId: string; count: number}>;\n },\n): Promise<number> {\n let released = 0;\n\n for (const release of params.releases) {\n if (release.count <= 0) continue;\n\n const decremented = await tx\n .update(reservations)\n .set({count: sql`${reservations.count} - ${release.count}`})\n .where(\n and(\n eq(reservations.id, release.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.count, release.count),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .returning({id: reservations.id});\n\n if (decremented.length > 0) {\n released += release.count;\n continue;\n }\n\n const deleted = await tx\n .delete(reservations)\n .where(\n and(\n eq(reservations.id, release.reservationId),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n sql`${reservations.count} <= ${release.count}`,\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .returning({count: reservations.count});\n\n released += deleted.reduce((total, row) => total + row.count, 0);\n }\n\n return released;\n}\n\nfunction deductProvisionerReservations(\n templates: NormalizedTemplate[],\n activeReservations: {requiredLabels: string[]; reserved: number}[],\n): void {\n for (const reservation of sortReservationRows(activeReservations)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.reserved);\n }\n}\n\nfunction compareRunnerIds(left: {id: string}, right: {id: string}): number {\n return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;\n}\n\nfunction sortDemandRows(rows: DemandRow[]): DemandRow[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return a.oldestQueuedAt.getTime() - b.oldestQueuedAt.getTime();\n });\n}\n\nfunction sortReservationRows<T extends {requiredLabels: string[]}>(rows: T[]): T[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return labelKey(a.requiredLabels).localeCompare(labelKey(b.requiredLabels));\n });\n}\n\nfunction isSubset(requiredLabels: string[], availableLabels: string[]): boolean {\n return requiredLabels.every((label) => availableLabels.includes(label));\n}\n\nfunction drawSlots(templates: NormalizedTemplate[], count: number): void {\n let remaining = count;\n for (const template of templates) {\n if (remaining === 0) return;\n const used = Math.min(template.remainingSlots, remaining);\n template.remainingSlots -= used;\n remaining -= used;\n }\n}\n\nfunction labelKey(labels: string[]): string {\n return JSON.stringify(labels);\n}\n"],"names":["canonicalizeLabels","and","arrayContains","asc","eq","exists","gt","inArray","isNotNull","isNull","lt","notExists","notInArray","or","sql","recordProviderRunnerActivationOutcome","db","lockRunnerReservationAdvisoryKeysTx","terminalStates","pendingJobExecutions","provisionerCapabilitySnapshots","provisionerTokens","reservations","runnerActivationTokens","runnerControlSessions","providerRunners","pollDemandAndReserve","params","result","transaction","tx","pollDemandAndReserveTx","stats","execute","workspaceId","pollDemandAndReserveLockedTx","scope","pollInstallationDemandAndReserve","candidateWorkspaceIds","listInstallationDemandWorkspaceIds","eligibleWorkspaceIds","results","remainingMaxReservations","maxReservations","remainingTemplates","templates","map","template","labels","remainingSlots","availableSlots","signal","aborted","lockResult","locked","rows","newlyReservedUnits","provisionerId","ttlSeconds","activationGraceSeconds","undefined","capabilityWindowSeconds","push","consumeInstallationTemplateSlots","onReservations","reduce","total","reservation","count","newlyReservedCount","subtotal","flatMap","launchGrants","satisfyingTemplates","filter","isSubset","sort","a","b","length","templateKey","localeCompare","drawSlots","demandRows","select","requiredLabels","queued","oldestQueuedAt","createdAt","from","where","groupBy","row","Date","capabilityLabels","listActiveWorkspaceCapabilityLabelsTx","windowSeconds","demand","some","activeReservationRows","reserved","expiresAt","reservedByLabels","Map","labelKey","activeProvisionerReservationRows","listActiveProvisionerReservationRowsTx","deductProvisionerReservations","grants","workspaceIdField","sortDemandRows","get","unreserved","Math","max","capacity","grant","min","reservedAfterGrant","idleRunners","listIdleRunnerInstancesTx","boundCount","boundReservation","insert","values","kind","returning","id","Error","bindIdleRunnerInstancesTx","reservationId","launchCount","launchReservation","inserted","candidateRows","candidateIds","reservationIds","activeRows","orderBy","for","activeIds","activeIdSet","Set","usedRunnerRows","intendedReservationId","state","reservationReleasedAt","usedByReservation","runner","has","addUsedRunner","includes","used","size","pending","runnerId","runnerIds","add","set","canBindRunner","runnerSessionId","isBindableRunner","providerRunnerId","runnerInstanceId","closedAt","lockedRunners","selectIdleRunnerInstancesTx","launchKind","limit","retrySelection","Symbol","lockTx","candidateRunners","candidate","compareRunnerIds","error","idleRunnerIds","update","revokedAt","consumedAt","boundRunners","assignedAt","updatedAt","reboundCount","outcome","listQueuedDemandWorkspaceIds","innerJoin","advertisedAt","deleteExpiredReservations","expiredRows","deleteReservationsWithCleanupTx","expiredOnly","deleteReservationsByIds","ids","isAffectedRunner","affectedRunners","reservationRows","assignedRunnerIds","intendedRunnerIds","deleted","delete","releaseReservationUnits","released","release","releases","decremented","activeReservations","sortReservationRows","left","right","specificity","getTime","availableLabels","every","label","remaining","JSON","stringify"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/reservations.ts"],"sourcesContent":["import {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContains,\n asc,\n eq,\n exists,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n notExists,\n notInArray,\n or,\n sql,\n} from 'drizzle-orm';\nimport {recordProviderRunnerActivationOutcome} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {lockRunnerReservationAdvisoryKeysTx} from './reservation-locks.js';\nimport {terminalStates} from './runner-states.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {provisionerCapabilitySnapshots} from './schema/provisioner-capability-snapshots.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\nimport {runnerActivationTokens} from './schema/runner-activation-tokens.js';\nimport {runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {type providerRunnerLaunchKindEnum, providerRunners} from './schema/runner-instances.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport interface ReservationTemplate {\n templateKey: string;\n labels: string[];\n availableSlots: number;\n starting: number;\n running: number;\n}\n\nexport interface DemandStat {\n workspaceId?: string;\n labels: string[];\n queued: number;\n reserved: number;\n oldestQueuedAt: Date;\n}\n\nexport interface ReservationGrant {\n reservationId: string;\n workspaceId?: string;\n labels: string[];\n count: number;\n expiresAt: Date;\n}\n\nexport interface PollDemandAndReserveParams {\n workspaceId: string;\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n /** Lifetime of the short reservation that gives rebound runners time to activate. */\n activationGraceSeconds?: number;\n templates: ReservationTemplate[];\n capabilityWindowSeconds?: number;\n}\n\nexport interface InstallationPollDemandAndReserveParams {\n provisionerId: string;\n maxReservations: number;\n ttlSeconds: number;\n /** Lifetime of the short reservation that gives rebound runners time to activate. */\n activationGraceSeconds?: number;\n templates: ReservationTemplate[];\n capabilityWindowSeconds: number;\n eligibleWorkspaceIds: ReadonlySet<string>;\n signal?: AbortSignal;\n onReservations?: (reservations: ReservationGrant[]) => void;\n}\n\ntype DemandScope = 'installation' | 'workspace';\n\ninterface IdleRunnerCandidate {\n id: string;\n launchKind: (typeof providerRunnerLaunchKindEnum.enumValues)[number];\n}\n\ninterface BindableRunnerParams {\n provisionerId: string;\n workspaceId: string;\n requiredLabels: string[];\n scope: DemandScope;\n}\n\ninterface IdleRunnerSelectionParams extends BindableRunnerParams {\n count: number;\n}\n\ntype PollDemandAndReserveLockedParams = PollDemandAndReserveParams & {\n scope: DemandScope;\n};\n\ninterface NormalizedTemplate {\n templateKey: string;\n labels: string[];\n remainingSlots: number;\n}\n\ninterface DemandRow {\n requiredLabels: string[];\n queued: number;\n oldestQueuedAt: Date;\n}\n\ninterface NewReservationUnits {\n labels: string[];\n count: number;\n}\n\ninterface PollDemandAndReserveResult {\n stats: DemandStat[];\n /** Only launch reservations are exposed to the provisioner. */\n reservations: ReservationGrant[];\n /** Internal allocation accounting for bound and launch rows together. */\n newlyReservedUnits: NewReservationUnits[];\n}\n\nexport async function pollDemandAndReserve(\n params: PollDemandAndReserveParams,\n): Promise<{stats: DemandStat[]; reservations: ReservationGrant[]}> {\n const result = await db().transaction(async (tx) => {\n return await pollDemandAndReserveTx(tx, params);\n });\n return {stats: result.stats, reservations: result.reservations};\n}\n\nexport async function pollDemandAndReserveTx(\n tx: Tx,\n params: PollDemandAndReserveParams,\n): Promise<PollDemandAndReserveResult> {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId}))`);\n return await pollDemandAndReserveLockedTx(tx, {...params, scope: 'workspace'});\n}\n\nexport async function pollInstallationDemandAndReserve(\n params: InstallationPollDemandAndReserveParams,\n): Promise<{\n stats: DemandStat[];\n reservations: ReservationGrant[];\n newlyReservedCount?: number;\n}> {\n const candidateWorkspaceIds = await listInstallationDemandWorkspaceIds(\n params.eligibleWorkspaceIds,\n );\n const results: PollDemandAndReserveResult[] = [];\n let remainingMaxReservations = params.maxReservations;\n const remainingTemplates = params.templates.map((template) => ({\n ...template,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n for (const workspaceId of candidateWorkspaceIds) {\n if (params.signal?.aborted || remainingMaxReservations === 0) break;\n const result = await db().transaction(async (tx) => {\n const lockResult = await tx.execute<{locked: boolean}>(\n sql`select pg_try_advisory_xact_lock(hashtext(${workspaceId})) as locked`,\n );\n const locked = lockResult.rows[0];\n if (!locked?.locked) return {stats: [], reservations: [], newlyReservedUnits: []};\n return await pollDemandAndReserveLockedTx(tx, {\n workspaceId,\n provisionerId: params.provisionerId,\n maxReservations: remainingMaxReservations,\n ttlSeconds: params.ttlSeconds,\n ...(params.activationGraceSeconds !== undefined\n ? {activationGraceSeconds: params.activationGraceSeconds}\n : {}),\n templates: remainingTemplates.map((template) => ({\n ...template,\n availableSlots: template.remainingSlots,\n })),\n capabilityWindowSeconds: params.capabilityWindowSeconds,\n scope: 'installation',\n });\n });\n results.push(result);\n consumeInstallationTemplateSlots(remainingTemplates, result.reservations);\n params.onReservations?.(result.reservations);\n remainingMaxReservations -= result.newlyReservedUnits.reduce(\n (total, reservation) => total + reservation.count,\n 0,\n );\n }\n const newlyReservedCount = results.reduce(\n (total, result) =>\n total +\n result.newlyReservedUnits.reduce((subtotal, reservation) => subtotal + reservation.count, 0),\n 0,\n );\n return {\n stats: results.flatMap((result) => result.stats),\n reservations: results.flatMap((result) => result.reservations),\n ...(newlyReservedCount > 0 ? {newlyReservedCount} : {}),\n };\n}\n\nfunction consumeInstallationTemplateSlots(\n templates: NormalizedTemplate[],\n launchGrants: ReservationGrant[],\n): void {\n // Adopted runners are already included in the running count behind availableSlots.\n // Only units that still need a launch consume advertised template capacity.\n for (const reservation of launchGrants) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.labels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.count);\n }\n}\n\nasync function pollDemandAndReserveLockedTx(\n tx: Tx,\n params: PollDemandAndReserveLockedParams,\n): Promise<PollDemandAndReserveResult> {\n let demandRows = (\n await tx\n .select({\n requiredLabels: pendingJobExecutions.requiredLabels,\n queued: sql<number>`count(*)::int`,\n oldestQueuedAt: sql<Date | string>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(eq(pendingJobExecutions.workspaceId, params.workspaceId))\n .groupBy(pendingJobExecutions.requiredLabels)\n ).map((row) => ({\n ...row,\n oldestQueuedAt: new Date(row.oldestQueuedAt),\n }));\n if (params.capabilityWindowSeconds !== undefined) {\n const capabilityLabels = await listActiveWorkspaceCapabilityLabelsTx(tx, {\n workspaceId: params.workspaceId,\n windowSeconds: params.capabilityWindowSeconds,\n });\n demandRows = demandRows.filter(\n (demand) => !capabilityLabels.some((labels) => isSubset(demand.requiredLabels, labels)),\n );\n }\n\n const activeReservationRows = await tx\n .select({\n requiredLabels: reservations.requiredLabels,\n reserved: sql<number>`coalesce(sum(${reservations.count}), 0)::int`,\n })\n .from(reservations)\n .where(\n and(eq(reservations.workspaceId, params.workspaceId), gt(reservations.expiresAt, sql`now()`)),\n )\n .groupBy(reservations.requiredLabels);\n\n const reservedByLabels = new Map(\n activeReservationRows.map((row) => [labelKey(row.requiredLabels), row.reserved]),\n );\n const activeProvisionerReservationRows = await listActiveProvisionerReservationRowsTx(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n });\n\n const templates = params.templates.map((template) => ({\n templateKey: template.templateKey,\n labels: [...canonicalizeLabels(template.labels)],\n remainingSlots: template.availableSlots,\n }));\n deductProvisionerReservations(templates, activeProvisionerReservationRows);\n const stats: DemandStat[] = [];\n const grants: ReservationGrant[] = [];\n const newlyReservedUnits: NewReservationUnits[] = [];\n let remainingMaxReservations = params.maxReservations;\n const workspaceIdField =\n params.capabilityWindowSeconds === undefined ? {} : {workspaceId: params.workspaceId};\n\n for (const demand of sortDemandRows(demandRows)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(demand.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n\n if (satisfyingTemplates.length === 0) continue;\n\n const reserved = reservedByLabels.get(labelKey(demand.requiredLabels)) ?? 0;\n const unreserved = Math.max(0, demand.queued - reserved);\n const capacity = satisfyingTemplates.reduce(\n (total, template) => total + template.remainingSlots,\n 0,\n );\n const grant = Math.min(unreserved, capacity, remainingMaxReservations);\n let reservedAfterGrant = reserved;\n\n if (grant > 0 && params.maxReservations > 0) {\n const idleRunners = await listIdleRunnerInstancesTx(tx, {\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: grant,\n workspaceId: params.workspaceId,\n scope: params.scope,\n });\n\n remainingMaxReservations -= grant;\n\n const boundCount = idleRunners.length;\n if (boundCount > 0) {\n const [boundReservation] = await tx\n .insert(reservations)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: boundCount,\n kind: 'bound',\n expiresAt: sql`now() + (${params.activationGraceSeconds ?? params.ttlSeconds} || ' seconds')::interval`,\n })\n .returning({id: reservations.id});\n\n if (!boundReservation) throw new Error('Insert returned no rows');\n\n await bindIdleRunnerInstancesTx(tx, {\n provisionerId: params.provisionerId,\n reservationId: boundReservation.id,\n workspaceId: params.workspaceId,\n requiredLabels: demand.requiredLabels,\n scope: params.scope,\n idleRunners,\n });\n }\n\n const launchCount = grant - boundCount;\n drawSlots(satisfyingTemplates, launchCount);\n let launchReservation: {id: string; expiresAt: Date} | undefined;\n if (launchCount > 0) {\n const [inserted] = await tx\n .insert(reservations)\n .values({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n requiredLabels: demand.requiredLabels,\n count: launchCount,\n kind: 'launch',\n expiresAt: sql`now() + (${params.ttlSeconds} || ' seconds')::interval`,\n })\n .returning({id: reservations.id, expiresAt: reservations.expiresAt});\n\n if (!inserted) throw new Error('Insert returned no rows');\n launchReservation = inserted;\n }\n\n newlyReservedUnits.push({labels: demand.requiredLabels, count: grant});\n reservedAfterGrant += grant;\n if (launchReservation) {\n grants.push({\n reservationId: launchReservation.id,\n ...workspaceIdField,\n labels: demand.requiredLabels,\n count: launchCount,\n expiresAt: launchReservation.expiresAt,\n });\n }\n }\n\n stats.push({\n ...workspaceIdField,\n labels: demand.requiredLabels,\n queued: demand.queued,\n reserved: reservedAfterGrant,\n oldestQueuedAt: demand.oldestQueuedAt,\n });\n }\n\n return {stats, reservations: grants, newlyReservedUnits};\n}\n\nasync function listActiveProvisionerReservationRowsTx(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string},\n): Promise<Array<{requiredLabels: string[]; reserved: number}>> {\n const candidateRows = await tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n );\n const candidateIds = candidateRows.map((row) => row.id);\n if (candidateIds.length === 0) return [];\n\n // Assignment and provider-report transactions use this key before changing runner\n // links. Lock it before counting so an in-flight assignment cannot expose its unit twice.\n await lockRunnerReservationAdvisoryKeysTx(tx, {\n provisionerId: params.provisionerId,\n reservationIds: candidateIds,\n });\n\n const activeRows = await tx\n .select({\n id: reservations.id,\n requiredLabels: reservations.requiredLabels,\n count: reservations.count,\n })\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n )\n .orderBy(asc(reservations.id))\n .for('update');\n if (activeRows.length === 0) return [];\n\n const activeIds = activeRows.map((row) => row.id);\n const activeIdSet = new Set(activeIds);\n const usedRunnerRows = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.reservationReleasedAt),\n or(\n and(\n inArray(providerRunners.reservationId, activeIds),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n and(\n inArray(providerRunners.intendedReservationId, activeIds),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n ),\n ),\n );\n const usedByReservation = new Map<string, Set<string>>();\n for (const runner of usedRunnerRows) {\n if (runner.reservationId && activeIdSet.has(runner.reservationId)) {\n addUsedRunner(usedByReservation, runner.reservationId, runner.id);\n }\n if (runner.intendedReservationId && activeIdSet.has(runner.intendedReservationId)) {\n addUsedRunner(usedByReservation, runner.intendedReservationId, runner.id);\n }\n }\n\n return activeRows.flatMap((reservation) => {\n const used = usedByReservation.get(reservation.id)?.size ?? 0;\n const pending = Math.max(0, reservation.count - used);\n return pending > 0 ? [{requiredLabels: reservation.requiredLabels, reserved: pending}] : [];\n });\n}\n\nfunction addUsedRunner(\n usedByReservation: Map<string, Set<string>>,\n reservationId: string,\n runnerId: string,\n): void {\n const runnerIds = usedByReservation.get(reservationId);\n if (runnerIds) runnerIds.add(runnerId);\n else usedByReservation.set(reservationId, new Set([runnerId]));\n}\n\n// An expired or missing reservation is stale. A live reservation protects a runner that is\n// still booting or waiting for its activation grace period.\nfunction canBindRunner(tx: Tx, params: BindableRunnerParams) {\n return and(\n or(\n and(isNull(providerRunners.workspaceId), isNull(providerRunners.reservationId)),\n and(\n isNotNull(providerRunners.reservationId),\n params.scope === 'installation'\n ? undefined\n : or(\n isNull(providerRunners.workspaceId),\n eq(providerRunners.workspaceId, params.workspaceId),\n ),\n notExists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.id, providerRunners.reservationId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n ),\n ),\n ),\n ),\n or(\n isNull(providerRunners.intendedReservationId),\n notExists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.id, providerRunners.intendedReservationId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n ),\n ),\n ),\n isNull(providerRunners.reservationReleasedAt),\n isNull(providerRunners.runnerSessionId),\n );\n}\n\nfunction isBindableRunner(tx: Tx, params: BindableRunnerParams) {\n return and(\n eq(providerRunners.provisionerId, params.provisionerId),\n canBindRunner(tx, params),\n isNotNull(providerRunners.providerRunnerId),\n eq(providerRunners.state, 'running'),\n arrayContains(providerRunners.labels, params.requiredLabels),\n exists(\n tx\n .select({id: runnerControlSessions.id})\n .from(runnerControlSessions)\n .where(\n and(\n eq(runnerControlSessions.runnerInstanceId, providerRunners.id),\n eq(runnerControlSessions.provisionerId, params.provisionerId),\n isNull(runnerControlSessions.closedAt),\n gt(runnerControlSessions.expiresAt, sql`now()`),\n ),\n ),\n ),\n );\n}\n\nasync function listIdleRunnerInstancesTx(\n tx: Tx,\n params: IdleRunnerSelectionParams & {count: number},\n): Promise<IdleRunnerCandidate[]> {\n const lockedRunners = await selectIdleRunnerInstancesTx(tx, params);\n if (lockedRunners.length === 0) return lockedRunners;\n\n // A SELECT ... FOR UPDATE can wake with a fresh target row but the original\n // statement snapshot for reservation subqueries. Re-check the full predicate\n // in a new statement while retaining the row locks from the first query.\n return await selectIdleRunnerInstancesTx(tx, {\n ...params,\n runnerIds: lockedRunners.map((runner) => runner.id),\n count: lockedRunners.length,\n });\n}\n\nasync function selectIdleRunnerInstancesTx(\n tx: Tx,\n params: IdleRunnerSelectionParams & {count: number; runnerIds?: string[]},\n): Promise<IdleRunnerCandidate[]> {\n if (params.runnerIds) {\n // The first pass retains the row locks. Recheck the full predicate in a fresh statement so\n // reservation subqueries see the state that was current when the lock was acquired.\n return await tx\n .select({id: providerRunners.id, launchKind: providerRunners.launchKind})\n .from(providerRunners)\n .where(and(inArray(providerRunners.id, params.runnerIds), isBindableRunner(tx, params)))\n .orderBy(asc(providerRunners.createdAt), asc(providerRunners.id))\n .limit(params.count);\n }\n\n // Select the oldest candidates first, but leave row locking to a second pass. The cleanup\n // path locks runner rows by id, so the locking pass must use that same order. A skipped row\n // rolls back only this nested savepoint and retries the bounded candidate scan, allowing the\n // next-oldest eligible runner to refill the grant without retaining a partial lock set.\n const retrySelection = Symbol('retry bindable runner selection');\n const idleRunners = await (async () => {\n while (true) {\n try {\n return await tx.transaction(async (lockTx) => {\n const candidateRunners = await lockTx\n .select({id: providerRunners.id, launchKind: providerRunners.launchKind})\n .from(providerRunners)\n .where(isBindableRunner(lockTx, params))\n .orderBy(asc(providerRunners.createdAt), asc(providerRunners.id))\n .limit(params.count);\n\n if (candidateRunners.length === 0) return candidateRunners;\n\n // PostgreSQL can acquire row locks before sorting a multi-row FOR UPDATE result. Lock\n // each selected candidate individually so both polling and cleanup use id order.\n const lockedRunners: typeof candidateRunners = [];\n for (const candidate of [...candidateRunners].sort(compareRunnerIds)) {\n const [runner] = await lockTx\n .select({id: providerRunners.id, launchKind: providerRunners.launchKind})\n .from(providerRunners)\n .where(and(eq(providerRunners.id, candidate.id), isBindableRunner(lockTx, params)))\n .for('update');\n if (runner) lockedRunners.push(runner);\n }\n\n if (lockedRunners.length !== candidateRunners.length) throw retrySelection;\n return lockedRunners;\n });\n } catch (error) {\n if (error !== retrySelection) throw error;\n }\n }\n })();\n\n return idleRunners;\n}\n\nasync function bindIdleRunnerInstancesTx(\n tx: Tx,\n params: {\n provisionerId: string;\n reservationId: string;\n workspaceId: string;\n requiredLabels: string[];\n scope: DemandScope;\n idleRunners: IdleRunnerCandidate[];\n },\n): Promise<void> {\n const idleRunnerIds = params.idleRunners.map((runner) => runner.id);\n\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n inArray(runnerActivationTokens.runnerInstanceId, idleRunnerIds),\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n ),\n );\n\n // listIdleRunnerInstancesTx re-checks the full eligibility predicate in a fresh statement\n // after acquiring row locks. Those locks prevent the validated set from changing before this\n // update runs.\n const boundRunners = await tx\n .update(providerRunners)\n .set({\n workspaceId: params.workspaceId,\n reservationId: params.reservationId,\n intendedReservationId: null,\n assignedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(and(inArray(providerRunners.id, idleRunnerIds), isBindableRunner(tx, params)))\n .returning({id: providerRunners.id, launchKind: providerRunners.launchKind});\n\n if (boundRunners.length !== params.idleRunners.length)\n throw new Error('Locked idle runner set changed before binding');\n\n const reboundCount = boundRunners.filter((runner) => runner.launchKind === 'demand').length;\n if (reboundCount > 0)\n recordProviderRunnerActivationOutcome({outcome: 'rebound', count: reboundCount});\n}\n\nasync function listInstallationDemandWorkspaceIds(eligibleWorkspaceIds: ReadonlySet<string>) {\n if (eligibleWorkspaceIds.size === 0) return [];\n const rows = await db()\n .select({\n workspaceId: pendingJobExecutions.workspaceId,\n oldestQueuedAt: sql<Date>`min(${pendingJobExecutions.createdAt})`,\n })\n .from(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.workspaceId, [...eligibleWorkspaceIds]))\n .groupBy(pendingJobExecutions.workspaceId)\n .orderBy(\n asc(sql`min(${pendingJobExecutions.createdAt})`),\n asc(pendingJobExecutions.workspaceId),\n );\n return rows.map((row) => row.workspaceId);\n}\n\nexport async function listQueuedDemandWorkspaceIds(): Promise<string[]> {\n const rows = await db()\n .select({workspaceId: pendingJobExecutions.workspaceId})\n .from(pendingJobExecutions)\n .groupBy(pendingJobExecutions.workspaceId);\n return rows.map((row) => row.workspaceId);\n}\n\nasync function listActiveWorkspaceCapabilityLabelsTx(\n tx: Tx,\n params: {workspaceId: string; windowSeconds: number},\n): Promise<string[][]> {\n const rows = await tx\n .select({labels: provisionerCapabilitySnapshots.labels})\n .from(provisionerCapabilitySnapshots)\n .innerJoin(\n provisionerTokens,\n eq(provisionerTokens.id, provisionerCapabilitySnapshots.provisionerId),\n )\n .where(\n and(\n eq(provisionerCapabilitySnapshots.workspaceId, params.workspaceId),\n eq(provisionerTokens.workspaceId, params.workspaceId),\n eq(provisionerTokens.scope, 'workspace'),\n sql`${provisionerCapabilitySnapshots.advertisedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n sql`${provisionerTokens.revokedAt} is null`,\n sql`(${provisionerTokens.expiresAt} is null or ${provisionerTokens.expiresAt} > now())`,\n ),\n );\n return rows.map((row) => row.labels);\n}\n\nexport async function deleteExpiredReservations(params?: {limit?: number}): Promise<number> {\n return await db().transaction(async (tx) => {\n const expiredRows = await tx\n .select({id: reservations.id})\n .from(reservations)\n .where(lt(reservations.expiresAt, sql`now()`))\n .orderBy(asc(reservations.expiresAt))\n .limit(params?.limit ?? 1000);\n return await deleteReservationsWithCleanupTx(\n tx,\n expiredRows.map((reservation) => reservation.id),\n {expiredOnly: true},\n );\n });\n}\n\nexport async function deleteReservationsByIds(ids: string[]): Promise<number> {\n if (ids.length === 0) return 0;\n\n return await db().transaction(async (tx) => {\n return await deleteReservationsWithCleanupTx(tx, ids);\n });\n}\n\nasync function deleteReservationsWithCleanupTx(\n tx: Tx,\n ids: string[],\n params: {expiredOnly?: boolean} = {},\n): Promise<number> {\n if (ids.length === 0) return 0;\n\n const isAffectedRunner = () =>\n or(\n and(\n inArray(providerRunners.reservationId, ids),\n isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n inArray(providerRunners.intendedReservationId, ids),\n );\n const candidateRunners = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n runnerSessionId: providerRunners.runnerSessionId,\n reservationReleasedAt: providerRunners.reservationReleasedAt,\n })\n .from(providerRunners)\n .where(isAffectedRunner())\n .orderBy(asc(providerRunners.id));\n const affectedRunners: typeof candidateRunners = [];\n for (const candidate of [...candidateRunners].sort(compareRunnerIds)) {\n const [runner] = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n runnerSessionId: providerRunners.runnerSessionId,\n reservationReleasedAt: providerRunners.reservationReleasedAt,\n })\n .from(providerRunners)\n .where(and(eq(providerRunners.id, candidate.id), isAffectedRunner()))\n .for('update');\n if (runner) affectedRunners.push(runner);\n }\n const reservationRows = await tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n inArray(reservations.id, ids),\n params.expiredOnly ? lt(reservations.expiresAt, sql`now()`) : undefined,\n ),\n )\n .for('update');\n const reservationIds = reservationRows.map((reservation) => reservation.id);\n\n if (reservationIds.length === 0) return 0;\n\n const assignedRunnerIds = affectedRunners\n .filter(\n (runner) =>\n runner.reservationId &&\n reservationIds.includes(runner.reservationId) &&\n !runner.runnerSessionId &&\n !runner.reservationReleasedAt,\n )\n .map((runner) => runner.id);\n const intendedRunnerIds = affectedRunners\n .filter(\n (runner) =>\n runner.intendedReservationId && reservationIds.includes(runner.intendedReservationId),\n )\n .map((runner) => runner.id);\n if (assignedRunnerIds.length > 0) {\n await tx\n .update(runnerActivationTokens)\n .set({revokedAt: sql`now()`})\n .where(\n and(\n inArray(runnerActivationTokens.runnerInstanceId, assignedRunnerIds),\n isNull(runnerActivationTokens.consumedAt),\n isNull(runnerActivationTokens.revokedAt),\n ),\n );\n await tx\n .update(providerRunners)\n .set({\n workspaceId: null,\n reservationId: null,\n assignedAt: null,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(providerRunners.id, assignedRunnerIds),\n isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n }\n if (intendedRunnerIds.length > 0) {\n await tx\n .update(providerRunners)\n .set({intendedReservationId: null, updatedAt: sql`now()`})\n .where(\n and(\n inArray(providerRunners.id, intendedRunnerIds),\n inArray(providerRunners.intendedReservationId, reservationIds),\n ),\n );\n }\n\n const deleted = await tx\n .delete(reservations)\n .where(inArray(reservations.id, reservationIds))\n .returning({id: reservations.id});\n\n return deleted.length;\n}\n\nexport async function releaseReservationUnits(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n releases: Array<{reservationId: string; count: number}>;\n },\n): Promise<number> {\n const releaseByReservationId = new Map<string, number>();\n for (const release of params.releases) {\n if (release.count <= 0) continue;\n releaseByReservationId.set(\n release.reservationId,\n (releaseByReservationId.get(release.reservationId) ?? 0) + release.count,\n );\n }\n const reservationIds = [...releaseByReservationId.keys()];\n if (reservationIds.length === 0) return 0;\n\n const releaseCount = sql<number>`CASE ${reservations.id}\n ${sql.join(\n [...releaseByReservationId].map(\n ([reservationId, count]) => sql`WHEN ${reservationId} THEN ${count}`,\n ),\n sql` `,\n )}\n ELSE 0\n END`;\n const scope = and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n inArray(reservations.id, reservationIds),\n gt(reservations.expiresAt, sql`now()`),\n );\n\n const decremented = await tx\n .update(reservations)\n .set({count: sql`${reservations.count} - ${releaseCount}`})\n .where(and(scope, gt(reservations.count, releaseCount)))\n .returning({id: reservations.id});\n const releasedFromDecremented = decremented.reduce(\n (total, row) => total + (releaseByReservationId.get(row.id) ?? 0),\n 0,\n );\n\n const decrementedIds = decremented.map((row) => row.id);\n const deleted = await tx\n .delete(reservations)\n .where(\n and(\n scope,\n sql`${reservations.count} <= ${releaseCount}`,\n decrementedIds.length > 0 ? notInArray(reservations.id, decrementedIds) : undefined,\n ),\n )\n .returning({count: reservations.count});\n const releasedFromDeleted = deleted.reduce((total, row) => total + row.count, 0);\n\n return releasedFromDeleted + releasedFromDecremented;\n}\n\nexport async function releaseTerminalRunnerInstanceReservationsByIds(\n tx: Tx,\n params: {\n workspaceId: string | null;\n provisionerId: string;\n providerRunnerIds?: string[];\n runnerInstanceIds?: string[];\n reportedAtByProviderRunnerId?: ReadonlyMap<string, Date>;\n requireUnlinkedSession?: boolean;\n /** Lock linked runners before rechecking terminal state for lease finalization. */\n requireTerminalState?: boolean;\n },\n): Promise<number> {\n if (\n (params.providerRunnerIds?.length ?? 0) === 0 &&\n (params.runnerInstanceIds?.length ?? 0) === 0\n )\n return 0;\n\n const reservationWorkspacePredicate =\n params.workspaceId === null\n ? sql``\n : sql`and ${eq(reservations.workspaceId, params.workspaceId)}`;\n const noRunningJobPredicate = notExists(\n tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId),\n params.workspaceId === null\n ? undefined\n : eq(runningJobExecutions.workspaceId, params.workspaceId),\n ),\n ),\n );\n const reportFreshnessPredicate =\n params.reportedAtByProviderRunnerId && params.reportedAtByProviderRunnerId.size > 0\n ? or(\n ...[...params.reportedAtByProviderRunnerId].map(([providerRunnerId, reportedAt]) =>\n and(\n eq(providerRunners.providerRunnerId, providerRunnerId),\n lte(providerRunners.reportedAt, reportedAt),\n ),\n ),\n )\n : undefined;\n const runnerIdentityPredicate = or(\n params.providerRunnerIds && params.providerRunnerIds.length > 0\n ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds)\n : undefined,\n params.runnerInstanceIds && params.runnerInstanceIds.length > 0\n ? inArray(providerRunners.id, params.runnerInstanceIds)\n : undefined,\n );\n\n // Assignment locks these keys before changing runner links. Acquire them before locking or\n // marking terminal runners so an assignment cannot consume a reservation concurrently with\n // this release.\n const reservationRowsToLock = await tx\n .select({\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n runnerIdentityPredicate,\n params.requireTerminalState === false\n ? undefined\n : inArray(providerRunners.state, terminalStates),\n or(\n isNotNull(providerRunners.reservationId),\n isNotNull(providerRunners.intendedReservationId),\n ),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n const reservationIdsToLock = [\n ...new Set(\n reservationRowsToLock.flatMap((row) =>\n [row.reservationId, row.intendedReservationId].filter(\n (reservationId): reservationId is string => reservationId !== null,\n ),\n ),\n ),\n ];\n await lockRunnerReservationAdvisoryKeysTx(tx, {\n provisionerId: params.provisionerId,\n reservationIds: reservationIdsToLock,\n });\n\n const rows = await tx\n .select({\n id: providerRunners.id,\n state: providerRunners.state,\n releaseReservationId: sql<string | null>`coalesce(\n (select ${reservations.id}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.intendedReservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate}),\n (select ${reservations.id}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.reservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate})\n )`,\n releaseReservationWorkspaceId: sql<string | null>`coalesce(\n (select ${reservations.workspaceId}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.intendedReservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate}),\n (select ${reservations.workspaceId}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.reservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate})\n )`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n runnerIdentityPredicate,\n params.requireTerminalState === false\n ? undefined\n : inArray(providerRunners.state, terminalStates),\n or(\n isNotNull(providerRunners.reservationId),\n isNotNull(providerRunners.intendedReservationId),\n ),\n params.workspaceId === null\n ? undefined\n : or(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n or(\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.reservationId),\n ),\n ),\n ),\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n ),\n ),\n ),\n ),\n and(\n isNull(providerRunners.workspaceId),\n isNotNull(providerRunners.intendedReservationId),\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n ),\n ),\n ),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n noRunningJobPredicate,\n reportFreshnessPredicate,\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .for('update');\n\n if (rows.length === 0) return 0;\n\n // The lease-finalization path deliberately locks active rows too. If a terminal report is\n // concurrently projecting the runner state, PostgreSQL rechecks this row after the lock and\n // lets cleanup observe the committed terminal state without a cross-module advisory lock.\n const terminalRows =\n params.requireTerminalState === false\n ? rows.filter((row) => terminalStates.some((terminalState) => terminalState === row.state))\n : rows;\n if (terminalRows.length === 0) return 0;\n\n const updated = await tx\n .update(providerRunners)\n .set({\n intendedReservationId: null,\n reservationReleasedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n terminalRows.map((row) => row.id),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n noRunningJobPredicate,\n reportFreshnessPredicate,\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .returning({id: providerRunners.id});\n\n const releasesByReservationId = new Map<\n string,\n {workspaceId: string; reservationId: string; count: number}\n >();\n const updatedIds = new Set(updated.map((row) => row.id));\n for (const row of terminalRows) {\n if (!updatedIds.has(row.id)) continue;\n if (!row.releaseReservationId || !row.releaseReservationWorkspaceId) continue;\n const key = `${row.releaseReservationWorkspaceId}:${row.releaseReservationId}`;\n const release = releasesByReservationId.get(key) ?? {\n workspaceId: row.releaseReservationWorkspaceId,\n reservationId: row.releaseReservationId,\n count: 0,\n };\n release.count += 1;\n releasesByReservationId.set(key, release);\n }\n\n if (releasesByReservationId.size === 0) return 0;\n\n const releasesByWorkspaceId = new Map<string, Array<{reservationId: string; count: number}>>();\n for (const release of releasesByReservationId.values()) {\n const releases = releasesByWorkspaceId.get(release.workspaceId) ?? [];\n releases.push({reservationId: release.reservationId, count: release.count});\n releasesByWorkspaceId.set(release.workspaceId, releases);\n }\n\n let released = 0;\n for (const [workspaceId, releases] of releasesByWorkspaceId) {\n released += await releaseReservationUnits(tx, {\n workspaceId,\n provisionerId: params.provisionerId,\n releases,\n });\n }\n return released;\n}\n\nfunction deductProvisionerReservations(\n templates: NormalizedTemplate[],\n activeReservations: {requiredLabels: string[]; reserved: number}[],\n): void {\n for (const reservation of sortReservationRows(activeReservations)) {\n const satisfyingTemplates = templates\n .filter((template) => isSubset(reservation.requiredLabels, template.labels))\n .sort(\n (a, b) => a.labels.length - b.labels.length || a.templateKey.localeCompare(b.templateKey),\n );\n drawSlots(satisfyingTemplates, reservation.reserved);\n }\n}\n\nfunction compareRunnerIds(left: {id: string}, right: {id: string}): number {\n return left.id < right.id ? -1 : left.id > right.id ? 1 : 0;\n}\n\nfunction sortDemandRows(rows: DemandRow[]): DemandRow[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return a.oldestQueuedAt.getTime() - b.oldestQueuedAt.getTime();\n });\n}\n\nfunction sortReservationRows<T extends {requiredLabels: string[]}>(rows: T[]): T[] {\n return [...rows].sort((a, b) => {\n const specificity = b.requiredLabels.length - a.requiredLabels.length;\n if (specificity !== 0) return specificity;\n return labelKey(a.requiredLabels).localeCompare(labelKey(b.requiredLabels));\n });\n}\n\nfunction isSubset(requiredLabels: string[], availableLabels: string[]): boolean {\n return requiredLabels.every((label) => availableLabels.includes(label));\n}\n\nfunction drawSlots(templates: NormalizedTemplate[], count: number): void {\n let remaining = count;\n for (const template of templates) {\n if (remaining === 0) return;\n const used = Math.min(template.remainingSlots, remaining);\n template.remainingSlots -= used;\n remaining -= used;\n }\n}\n\nfunction labelKey(labels: string[]): string {\n return JSON.stringify(labels);\n}\n"],"names":["canonicalizeLabels","and","arrayContains","asc","eq","exists","gt","inArray","isNotNull","isNull","lt","lte","notExists","notInArray","or","sql","recordProviderRunnerActivationOutcome","db","lockRunnerReservationAdvisoryKeysTx","terminalStates","pendingJobExecutions","provisionerCapabilitySnapshots","provisionerTokens","reservations","runnerActivationTokens","runnerControlSessions","providerRunners","runningJobExecutions","pollDemandAndReserve","params","result","transaction","tx","pollDemandAndReserveTx","stats","execute","workspaceId","pollDemandAndReserveLockedTx","scope","pollInstallationDemandAndReserve","candidateWorkspaceIds","listInstallationDemandWorkspaceIds","eligibleWorkspaceIds","results","remainingMaxReservations","maxReservations","remainingTemplates","templates","map","template","labels","remainingSlots","availableSlots","signal","aborted","lockResult","locked","rows","newlyReservedUnits","provisionerId","ttlSeconds","activationGraceSeconds","undefined","capabilityWindowSeconds","push","consumeInstallationTemplateSlots","onReservations","reduce","total","reservation","count","newlyReservedCount","subtotal","flatMap","launchGrants","satisfyingTemplates","filter","isSubset","sort","a","b","length","templateKey","localeCompare","drawSlots","demandRows","select","requiredLabels","queued","oldestQueuedAt","createdAt","from","where","groupBy","row","Date","capabilityLabels","listActiveWorkspaceCapabilityLabelsTx","windowSeconds","demand","some","activeReservationRows","reserved","expiresAt","reservedByLabels","Map","labelKey","activeProvisionerReservationRows","listActiveProvisionerReservationRowsTx","deductProvisionerReservations","grants","workspaceIdField","sortDemandRows","get","unreserved","Math","max","capacity","grant","min","reservedAfterGrant","idleRunners","listIdleRunnerInstancesTx","boundCount","boundReservation","insert","values","kind","returning","id","Error","bindIdleRunnerInstancesTx","reservationId","launchCount","launchReservation","inserted","candidateRows","candidateIds","reservationIds","activeRows","orderBy","for","activeIds","activeIdSet","Set","usedRunnerRows","intendedReservationId","reservationReleasedAt","state","usedByReservation","runner","has","addUsedRunner","used","size","pending","runnerId","runnerIds","add","set","canBindRunner","runnerSessionId","isBindableRunner","providerRunnerId","runnerInstanceId","closedAt","lockedRunners","selectIdleRunnerInstancesTx","launchKind","limit","retrySelection","Symbol","lockTx","candidateRunners","candidate","compareRunnerIds","error","idleRunnerIds","update","revokedAt","consumedAt","boundRunners","assignedAt","updatedAt","reboundCount","outcome","listQueuedDemandWorkspaceIds","innerJoin","advertisedAt","deleteExpiredReservations","expiredRows","deleteReservationsWithCleanupTx","expiredOnly","deleteReservationsByIds","ids","isAffectedRunner","affectedRunners","reservationRows","assignedRunnerIds","includes","intendedRunnerIds","deleted","delete","releaseReservationUnits","releaseByReservationId","release","releases","keys","releaseCount","join","decremented","releasedFromDecremented","decrementedIds","releasedFromDeleted","releaseTerminalRunnerInstanceReservationsByIds","providerRunnerIds","runnerInstanceIds","reservationWorkspacePredicate","noRunningJobPredicate","reportFreshnessPredicate","reportedAtByProviderRunnerId","reportedAt","runnerIdentityPredicate","reservationRowsToLock","requireTerminalState","reservationIdsToLock","releaseReservationId","releaseReservationWorkspaceId","requireUnlinkedSession","terminalRows","terminalState","updated","releasesByReservationId","updatedIds","key","releasesByWorkspaceId","released","activeReservations","sortReservationRows","left","right","specificity","getTime","availableLabels","every","label","remaining","JSON","stringify"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-assignments.d.ts","sourceRoot":"","sources":["../../src/db/runner-assignments.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,mCAAmC,EACxC,KAAK,uBAAuB,EAE7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAQhC,gGAAgG;AAChG,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOpB;AAED,UAAU,6BAA6B;IACrC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,0BAA0B,EAAE,mCAAmC,EAAE,CAAC;CACnE;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,EAAE,EACN,MAAM,EAAE;IACN,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,EAAE,uBAAuB,CAAC;CAClC,GACA,OAAO,CAAC,6BAA6B,CAAC,
|
|
1
|
+
{"version":3,"file":"runner-assignments.d.ts","sourceRoot":"","sources":["../../src/db/runner-assignments.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,mCAAmC,EACxC,KAAK,uBAAuB,EAE7B,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAQhC,gGAAgG;AAChG,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAOpB;AAED,UAAU,6BAA6B;IACrC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,0BAA0B,EAAE,mCAAmC,EAAE,CAAC;CACnE;AAED,wBAAsB,uBAAuB,CAC3C,EAAE,EAAE,EAAE,EACN,MAAM,EAAE;IACN,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,OAAO,EAAE,uBAAuB,CAAC;CAClC,GACA,OAAO,CAAC,6BAA6B,CAAC,CAsLxC;AAED,MAAM,MAAM,sCAAsC,GAC9C,uBAAuB,GACvB,2BAA2B,GAC3B,qBAAqB,GACrB,oBAAoB,CAAC;AAEzB,MAAM,WAAW,mCAAmC;IAClD,qBAAqB,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,wBAAwB,EAAE,GAAG,CAC3B,MAAM,EACN;QAAC,MAAM,EAAE,sCAAsC,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAChE,CAAC;CACH;AAED,wBAAsB,mCAAmC,CACvD,EAAE,EAAE,EAAE,EACN,MAAM,EAAE;IACN,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,SAAS;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,EAAE,CAAC;CAC7D,EACD,OAAO,GAAE;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAM,GAC1C,OAAO,CAAC,mCAAmC,CAAC,CAiI9C"}
|
|
@@ -73,7 +73,9 @@ export async function assignRunnerInstancesTx(tx, params) {
|
|
|
73
73
|
const newRunnerIds = newRunners.map((runner)=>runner.id);
|
|
74
74
|
const assignedCount = await tx.select({
|
|
75
75
|
count: sql`count(*)::int`
|
|
76
|
-
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), notInArray(providerRunners.id, newRunnerIds), or(and(eq(providerRunners.reservationId, reservation.id), isNull(providerRunners.reservationReleasedAt)
|
|
76
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), notInArray(providerRunners.id, newRunnerIds), or(and(eq(providerRunners.reservationId, reservation.id), isNull(providerRunners.reservationReleasedAt), notInArray(providerRunners.state, [
|
|
77
|
+
...terminalStates
|
|
78
|
+
])), and(eq(providerRunners.intendedReservationId, reservation.id), isNull(providerRunners.reservationReleasedAt), notInArray(providerRunners.state, [
|
|
77
79
|
...terminalStates
|
|
78
80
|
])))));
|
|
79
81
|
if ((assignedCount[0]?.count ?? 0) + newRunners.length > reservation.count) throw new RunnerInstanceNotAssignableError(newRunners[0]?.id ?? '', 'capacity-exhausted');
|
|
@@ -157,9 +159,10 @@ export async function validateRunnerReservationCapacityTx(tx, params, options =
|
|
|
157
159
|
const usedRunnerRows = await tx.select({
|
|
158
160
|
id: providerRunners.id,
|
|
159
161
|
reservationId: providerRunners.reservationId,
|
|
160
|
-
intendedReservationId: providerRunners.intendedReservationId
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
intendedReservationId: providerRunners.intendedReservationId
|
|
163
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), isNull(providerRunners.reservationReleasedAt), or(and(inArray(providerRunners.reservationId, reservationIds), notInArray(providerRunners.state, [
|
|
164
|
+
...terminalStates
|
|
165
|
+
])), and(inArray(providerRunners.intendedReservationId, reservationIds), notInArray(providerRunners.state, [
|
|
163
166
|
...terminalStates
|
|
164
167
|
])))));
|
|
165
168
|
for (const runner of usedRunnerRows){
|
|
@@ -168,7 +171,7 @@ export async function validateRunnerReservationCapacityTx(tx, params, options =
|
|
|
168
171
|
usedRunnerIds.add(runner.id);
|
|
169
172
|
usedRunnerIdsByReservation.set(runner.reservationId, usedRunnerIds);
|
|
170
173
|
}
|
|
171
|
-
if (runner.intendedReservationId && requestedReservationIds.has(runner.intendedReservationId)
|
|
174
|
+
if (runner.intendedReservationId && requestedReservationIds.has(runner.intendedReservationId)) {
|
|
172
175
|
const usedRunnerIds = usedRunnerIdsByReservation.get(runner.intendedReservationId) ?? new Set();
|
|
173
176
|
usedRunnerIds.add(runner.id);
|
|
174
177
|
usedRunnerIdsByReservation.set(runner.intendedReservationId, usedRunnerIds);
|