@shipfox/api-runners 9.3.0 → 10.1.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 +46 -0
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/core/runner-activation.d.ts +6 -0
- package/dist/core/runner-activation.d.ts.map +1 -1
- package/dist/core/runner-activation.js +20 -19
- package/dist/core/runner-activation.js.map +1 -1
- package/dist/core/runner-control-sessions.d.ts +2 -1
- package/dist/core/runner-control-sessions.d.ts.map +1 -1
- package/dist/core/runner-control-sessions.js +65 -19
- package/dist/core/runner-control-sessions.js.map +1 -1
- package/dist/db/db.d.ts +34 -0
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/job-executions.d.ts +7 -0
- package/dist/db/job-executions.d.ts.map +1 -1
- package/dist/db/job-executions.js +25 -0
- package/dist/db/job-executions.js.map +1 -1
- package/dist/db/runner-assignments.d.ts +6 -0
- package/dist/db/runner-assignments.d.ts.map +1 -1
- package/dist/db/runner-assignments.js +57 -42
- package/dist/db/runner-assignments.js.map +1 -1
- package/dist/db/runner-instances.d.ts.map +1 -1
- package/dist/db/runner-instances.js +64 -19
- package/dist/db/runner-instances.js.map +1 -1
- package/dist/db/schema/runner-instances.d.ts +17 -0
- package/dist/db/schema/runner-instances.d.ts.map +1 -1
- package/dist/db/schema/runner-instances.js +3 -0
- package/dist/db/schema/runner-instances.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/presentation/inter-module.d.ts.map +1 -1
- package/dist/presentation/inter-module.js +7 -2
- package/dist/presentation/inter-module.js.map +1 -1
- package/dist/presentation/routes/runner-enrollment.d.ts +9 -0
- package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
- package/dist/presentation/routes/runner-enrollment.js +36 -23
- package/dist/presentation/routes/runner-enrollment.js.map +1 -1
- package/dist/tsconfig.test.tsbuildinfo +1 -1
- package/drizzle/0001_intended_reservation.sql +3 -0
- package/drizzle/meta/0001_snapshot.json +2093 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +7 -7
- package/src/config.test.ts +11 -0
- package/src/config.ts +1 -1
- package/src/core/runner-activation.ts +48 -38
- package/src/core/runner-control-sessions.ts +115 -33
- package/src/db/index.ts +1 -0
- package/src/db/job-executions.ts +28 -0
- package/src/db/runner-assignments.test.ts +81 -0
- package/src/db/runner-assignments.ts +134 -86
- package/src/db/runner-instances.test.ts +182 -0
- package/src/db/runner-instances.ts +123 -28
- package/src/db/schema/runner-instances.ts +9 -0
- package/src/index.ts +1 -0
- package/src/presentation/inter-module.ts +4 -0
- package/src/presentation/routes/poll-demand.test.ts +2 -2
- package/src/presentation/routes/runner-enrollment.test.ts +144 -1
- package/src/presentation/routes/runner-enrollment.ts +40 -20
- package/tsconfig.build.tsbuildinfo +1 -1
package/dist/db/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { closeDb, db, schema } from './db.js';
|
|
|
2
2
|
export type { CreateEphemeralRegistrationTokenParams, DeleteExpiredEphemeralRegistrationTokensParams, } from './ephemeral-registration-tokens.js';
|
|
3
3
|
export { createEphemeralRegistrationToken, createRunnerSessionConsumingEphemeralToken, deleteExpiredEphemeralRegistrationTokens, resolveEphemeralRegistrationTokenByHash, } from './ephemeral-registration-tokens.js';
|
|
4
4
|
export type { ClaimedJobExecution, EnqueueJobExecutionParams, RunnerInstanceBoundJobExecution, } from './job-executions.js';
|
|
5
|
-
export { cancelRunnerJobs, claimPendingJobExecution, enqueueJobExecution, expireStuckJobExecutions, isJobLeaseActive, listActiveRunningJobExecutions, listRunningJobExecutionsByRunnerInstanceTx, recordHeartbeat, releaseJobExecution, } from './job-executions.js';
|
|
5
|
+
export { cancelRunnerJobs, claimPendingJobExecution, enqueueJobExecution, expireStuckJobExecutions, getWorkspaceJobCounts, isJobLeaseActive, listActiveRunningJobExecutions, listRunningJobExecutionsByRunnerInstanceTx, recordHeartbeat, releaseJobExecution, } from './job-executions.js';
|
|
6
6
|
export type { CreateManualRegistrationTokenParams } from './manual-registration-tokens.js';
|
|
7
7
|
export { createManualRegistrationToken, listUsableManualRegistrationTokensByWorkspaceId, resolveManualRegistrationTokenByHash, revokeManualRegistrationToken, } from './manual-registration-tokens.js';
|
|
8
8
|
export { hasActiveWorkspaceProvisionerCapability, listActiveWorkspaceProvisionerCapabilitySnapshots, listStaleWorkspaceProvisionerCapabilitySnapshots, publishWorkspaceProvisionerCapabilitySnapshot, } from './provisioner-capability-snapshots.js';
|
package/dist/db/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,YAAY,EACV,sCAAsC,EACtC,8CAA8C,GAC/C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,gCAAgC,EAChC,0CAA0C,EAC1C,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EACV,mBAAmB,EACnB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,EACxB,gBAAgB,EAChB,8BAA8B,EAC9B,0CAA0C,EAC1C,eAAe,EACf,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAC,mCAAmC,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EACL,6BAA6B,EAC7B,+CAA+C,EAC/C,oCAAoC,EACpC,6BAA6B,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,uCAAuC,EACvC,iDAAiD,EACjD,gDAAgD,EAChD,6CAA6C,GAC9C,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EAAC,4BAA4B,EAAC,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,wCAAwC,EACxC,6BAA6B,EAC7B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,YAAY,EACV,iCAAiC,EACjC,8BAA8B,EAC9B,gCAAgC,EAChC,8BAA8B,EAC9B,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,mCAAmC,GACpC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,8BAA8B,EAC9B,eAAe,EACf,0CAA0C,EAC1C,yBAAyB,EACzB,oCAAoC,EACpC,+BAA+B,EAC/B,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAC,mBAAmB,EAAE,2BAA2B,EAAC,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAC,qBAAqB,EAAE,qBAAqB,EAAC,MAAM,qCAAqC,CAAC;AAEjG,eAAO,MAAM,cAAc,QAAoE,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,OAAO,EAAE,EAAE,EAAE,MAAM,EAAC,MAAM,SAAS,CAAC;AAC5C,YAAY,EACV,sCAAsC,EACtC,8CAA8C,GAC/C,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EACL,gCAAgC,EAChC,0CAA0C,EAC1C,wCAAwC,EACxC,uCAAuC,GACxC,MAAM,oCAAoC,CAAC;AAC5C,YAAY,EACV,mBAAmB,EACnB,yBAAyB,EACzB,+BAA+B,GAChC,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,gBAAgB,EAChB,8BAA8B,EAC9B,0CAA0C,EAC1C,eAAe,EACf,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAC,mCAAmC,EAAC,MAAM,iCAAiC,CAAC;AACzF,OAAO,EACL,6BAA6B,EAC7B,+CAA+C,EAC/C,oCAAoC,EACpC,6BAA6B,GAC9B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EACL,uCAAuC,EACvC,iDAAiD,EACjD,gDAAgD,EAChD,6CAA6C,GAC9C,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EAAC,4BAA4B,EAAC,MAAM,yBAAyB,CAAC;AAC1E,OAAO,EACL,sBAAsB,EACtB,2BAA2B,EAC3B,wCAAwC,EACxC,6BAA6B,EAC7B,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EACL,uBAAuB,EACvB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,0BAA0B,EAC1B,gBAAgB,EAChB,mBAAmB,GACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EACL,yBAAyB,EACzB,uBAAuB,EACvB,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAC,qBAAqB,EAAC,MAAM,yBAAyB,CAAC;AAC9D,YAAY,EACV,iCAAiC,EACjC,8BAA8B,EAC9B,gCAAgC,EAChC,8BAA8B,EAC9B,2BAA2B,EAC3B,yBAAyB,EACzB,6BAA6B,EAC7B,mCAAmC,GACpC,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,8BAA8B,EAC9B,eAAe,EACf,0CAA0C,EAC1C,yBAAyB,EACzB,oCAAoC,EACpC,+BAA+B,EAC/B,wBAAwB,EACxB,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EACV,yBAAyB,EACzB,iCAAiC,GAClC,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAC,mBAAmB,EAAE,2BAA2B,EAAC,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAC,qBAAqB,EAAE,qBAAqB,EAAC,MAAM,qCAAqC,CAAC;AAEjG,eAAO,MAAM,cAAc,QAAoE,CAAC"}
|
package/dist/db/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { dirname, resolve } from 'node:path';
|
|
|
2
2
|
import { fileURLToPath } from 'node:url';
|
|
3
3
|
export { closeDb, db, schema } from './db.js';
|
|
4
4
|
export { createEphemeralRegistrationToken, createRunnerSessionConsumingEphemeralToken, deleteExpiredEphemeralRegistrationTokens, resolveEphemeralRegistrationTokenByHash } from './ephemeral-registration-tokens.js';
|
|
5
|
-
export { cancelRunnerJobs, claimPendingJobExecution, enqueueJobExecution, expireStuckJobExecutions, isJobLeaseActive, listActiveRunningJobExecutions, listRunningJobExecutionsByRunnerInstanceTx, recordHeartbeat, releaseJobExecution } from './job-executions.js';
|
|
5
|
+
export { cancelRunnerJobs, claimPendingJobExecution, enqueueJobExecution, expireStuckJobExecutions, getWorkspaceJobCounts, isJobLeaseActive, listActiveRunningJobExecutions, listRunningJobExecutionsByRunnerInstanceTx, recordHeartbeat, releaseJobExecution } from './job-executions.js';
|
|
6
6
|
export { createManualRegistrationToken, listUsableManualRegistrationTokensByWorkspaceId, resolveManualRegistrationTokenByHash, revokeManualRegistrationToken } from './manual-registration-tokens.js';
|
|
7
7
|
export { hasActiveWorkspaceProvisionerCapability, listActiveWorkspaceProvisionerCapabilitySnapshots, listStaleWorkspaceProvisionerCapabilitySnapshots, publishWorkspaceProvisionerCapabilitySnapshot } from './provisioner-capability-snapshots.js';
|
|
8
8
|
export { createProvisionerToken, listActiveProvisionerTokens, listUsableProvisionerTokensByWorkspaceId, resolveProvisionerTokenByHash, revokeProvisionerToken, touchProvisionerLastSeen } from './provisioner-tokens.js';
|
package/dist/db/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport type {\n CreateEphemeralRegistrationTokenParams,\n DeleteExpiredEphemeralRegistrationTokensParams,\n} from './ephemeral-registration-tokens.js';\nexport {\n createEphemeralRegistrationToken,\n createRunnerSessionConsumingEphemeralToken,\n deleteExpiredEphemeralRegistrationTokens,\n resolveEphemeralRegistrationTokenByHash,\n} from './ephemeral-registration-tokens.js';\nexport type {\n ClaimedJobExecution,\n EnqueueJobExecutionParams,\n RunnerInstanceBoundJobExecution,\n} from './job-executions.js';\nexport {\n cancelRunnerJobs,\n claimPendingJobExecution,\n enqueueJobExecution,\n expireStuckJobExecutions,\n isJobLeaseActive,\n listActiveRunningJobExecutions,\n listRunningJobExecutionsByRunnerInstanceTx,\n recordHeartbeat,\n releaseJobExecution,\n} from './job-executions.js';\nexport type {CreateManualRegistrationTokenParams} from './manual-registration-tokens.js';\nexport {\n createManualRegistrationToken,\n listUsableManualRegistrationTokensByWorkspaceId,\n resolveManualRegistrationTokenByHash,\n revokeManualRegistrationToken,\n} from './manual-registration-tokens.js';\nexport {\n hasActiveWorkspaceProvisionerCapability,\n listActiveWorkspaceProvisionerCapabilitySnapshots,\n listStaleWorkspaceProvisionerCapabilitySnapshots,\n publishWorkspaceProvisionerCapabilitySnapshot,\n} from './provisioner-capability-snapshots.js';\nexport type {CreateProvisionerTokenParams} from './provisioner-tokens.js';\nexport {\n createProvisionerToken,\n listActiveProvisionerTokens,\n listUsableProvisionerTokensByWorkspaceId,\n resolveProvisionerTokenByHash,\n revokeProvisionerToken,\n touchProvisionerLastSeen,\n} from './provisioner-tokens.js';\nexport {\n consumeRunnersRateLimit,\n pruneExpiredRunnersRateLimits,\n} from './rate-limits.js';\nexport type {\n DemandStat,\n PollDemandAndReserveParams,\n ReservationGrant,\n ReservationTemplate,\n} from './reservations.js';\nexport {\n deleteExpiredReservations,\n deleteReservationsByIds,\n pollDemandAndReserve,\n releaseReservationUnits,\n} from './reservations.js';\nexport {assignRunnerInstances} from './runner-assignments.js';\nexport type {\n ActiveRunnerInstanceTemplateCount,\n ReapStaleRunnerInstancesResult,\n ReconcileRunnerInstancesDbResult,\n ReconcileRunnerInstancesParams,\n ReportRunnerInstancesParams,\n RunnerInstanceReportEvent,\n RunnerInstanceTerminateIntent,\n RunnerInstanceTerminateIntentReason,\n} from './runner-instances.js';\nexport {\n attachRunnerInstanceProviderId,\n isTerminalState,\n listActiveRunnerInstanceCountsByTemplateTx,\n listActiveRunnerInstances,\n listProvisionerTerminateIntentRowsTx,\n listProvisionerTerminateIntents,\n reapStaleRunnerInstances,\n reconcileRunnerInstances,\n reportRunnerInstances,\n} from './runner-instances.js';\nexport type {\n CreateRunnerSessionParams,\n DeleteExpiredRunnerSessionsParams,\n} from './runner-sessions.js';\nexport {createRunnerSession, deleteExpiredRunnerSessions} from './runner-sessions.js';\nexport {runnersOutbox} from './schema/outbox.js';\nexport {runnerBootstrapTokens, runnerControlSessions} from './schema/runner-control-sessions.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","createEphemeralRegistrationToken","createRunnerSessionConsumingEphemeralToken","deleteExpiredEphemeralRegistrationTokens","resolveEphemeralRegistrationTokenByHash","cancelRunnerJobs","claimPendingJobExecution","enqueueJobExecution","expireStuckJobExecutions","isJobLeaseActive","listActiveRunningJobExecutions","listRunningJobExecutionsByRunnerInstanceTx","recordHeartbeat","releaseJobExecution","createManualRegistrationToken","listUsableManualRegistrationTokensByWorkspaceId","resolveManualRegistrationTokenByHash","revokeManualRegistrationToken","hasActiveWorkspaceProvisionerCapability","listActiveWorkspaceProvisionerCapabilitySnapshots","listStaleWorkspaceProvisionerCapabilitySnapshots","publishWorkspaceProvisionerCapabilitySnapshot","createProvisionerToken","listActiveProvisionerTokens","listUsableProvisionerTokensByWorkspaceId","resolveProvisionerTokenByHash","revokeProvisionerToken","touchProvisionerLastSeen","consumeRunnersRateLimit","pruneExpiredRunnersRateLimits","deleteExpiredReservations","deleteReservationsByIds","pollDemandAndReserve","releaseReservationUnits","assignRunnerInstances","attachRunnerInstanceProviderId","isTerminalState","listActiveRunnerInstanceCountsByTemplateTx","listActiveRunnerInstances","listProvisionerTerminateIntentRowsTx","listProvisionerTerminateIntents","reapStaleRunnerInstances","reconcileRunnerInstances","reportRunnerInstances","createRunnerSession","deleteExpiredRunnerSessions","runnersOutbox","runnerBootstrapTokens","runnerControlSessions","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAK5C,SACEC,gCAAgC,EAChCC,0CAA0C,EAC1CC,wCAAwC,EACxCC,uCAAuC,QAClC,qCAAqC;AAM5C,SACEC,gBAAgB,EAChBC,wBAAwB,EACxBC,mBAAmB,EACnBC,wBAAwB,EACxBC,gBAAgB,EAChBC,8BAA8B,EAC9BC,0CAA0C,EAC1CC,eAAe,EACfC,mBAAmB,QACd,sBAAsB;AAE7B,SACEC,6BAA6B,EAC7BC,+CAA+C,EAC/CC,oCAAoC,EACpCC,6BAA6B,QACxB,kCAAkC;AACzC,SACEC,uCAAuC,EACvCC,iDAAiD,EACjDC,gDAAgD,EAChDC,6CAA6C,QACxC,wCAAwC;AAE/C,SACEC,sBAAsB,EACtBC,2BAA2B,EAC3BC,wCAAwC,EACxCC,6BAA6B,EAC7BC,sBAAsB,EACtBC,wBAAwB,QACnB,0BAA0B;AACjC,SACEC,uBAAuB,EACvBC,6BAA6B,QACxB,mBAAmB;AAO1B,SACEC,yBAAyB,EACzBC,uBAAuB,EACvBC,oBAAoB,EACpBC,uBAAuB,QAClB,oBAAoB;AAC3B,SAAQC,qBAAqB,QAAO,0BAA0B;AAW9D,SACEC,8BAA8B,EAC9BC,eAAe,EACfC,0CAA0C,EAC1CC,yBAAyB,EACzBC,oCAAoC,EACpCC,+BAA+B,EAC/BC,wBAAwB,EACxBC,wBAAwB,EACxBC,qBAAqB,QAChB,wBAAwB;AAK/B,SAAQC,mBAAmB,EAAEC,2BAA2B,QAAO,uBAAuB;AACtF,SAAQC,aAAa,QAAO,qBAAqB;AACjD,SAAQC,qBAAqB,EAAEC,qBAAqB,QAAO,sCAAsC;AAEjG,OAAO,MAAMC,
|
|
1
|
+
{"version":3,"sources":["../../src/db/index.ts"],"sourcesContent":["import {dirname, resolve} from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nexport {closeDb, db, schema} from './db.js';\nexport type {\n CreateEphemeralRegistrationTokenParams,\n DeleteExpiredEphemeralRegistrationTokensParams,\n} from './ephemeral-registration-tokens.js';\nexport {\n createEphemeralRegistrationToken,\n createRunnerSessionConsumingEphemeralToken,\n deleteExpiredEphemeralRegistrationTokens,\n resolveEphemeralRegistrationTokenByHash,\n} from './ephemeral-registration-tokens.js';\nexport type {\n ClaimedJobExecution,\n EnqueueJobExecutionParams,\n RunnerInstanceBoundJobExecution,\n} from './job-executions.js';\nexport {\n cancelRunnerJobs,\n claimPendingJobExecution,\n enqueueJobExecution,\n expireStuckJobExecutions,\n getWorkspaceJobCounts,\n isJobLeaseActive,\n listActiveRunningJobExecutions,\n listRunningJobExecutionsByRunnerInstanceTx,\n recordHeartbeat,\n releaseJobExecution,\n} from './job-executions.js';\nexport type {CreateManualRegistrationTokenParams} from './manual-registration-tokens.js';\nexport {\n createManualRegistrationToken,\n listUsableManualRegistrationTokensByWorkspaceId,\n resolveManualRegistrationTokenByHash,\n revokeManualRegistrationToken,\n} from './manual-registration-tokens.js';\nexport {\n hasActiveWorkspaceProvisionerCapability,\n listActiveWorkspaceProvisionerCapabilitySnapshots,\n listStaleWorkspaceProvisionerCapabilitySnapshots,\n publishWorkspaceProvisionerCapabilitySnapshot,\n} from './provisioner-capability-snapshots.js';\nexport type {CreateProvisionerTokenParams} from './provisioner-tokens.js';\nexport {\n createProvisionerToken,\n listActiveProvisionerTokens,\n listUsableProvisionerTokensByWorkspaceId,\n resolveProvisionerTokenByHash,\n revokeProvisionerToken,\n touchProvisionerLastSeen,\n} from './provisioner-tokens.js';\nexport {\n consumeRunnersRateLimit,\n pruneExpiredRunnersRateLimits,\n} from './rate-limits.js';\nexport type {\n DemandStat,\n PollDemandAndReserveParams,\n ReservationGrant,\n ReservationTemplate,\n} from './reservations.js';\nexport {\n deleteExpiredReservations,\n deleteReservationsByIds,\n pollDemandAndReserve,\n releaseReservationUnits,\n} from './reservations.js';\nexport {assignRunnerInstances} from './runner-assignments.js';\nexport type {\n ActiveRunnerInstanceTemplateCount,\n ReapStaleRunnerInstancesResult,\n ReconcileRunnerInstancesDbResult,\n ReconcileRunnerInstancesParams,\n ReportRunnerInstancesParams,\n RunnerInstanceReportEvent,\n RunnerInstanceTerminateIntent,\n RunnerInstanceTerminateIntentReason,\n} from './runner-instances.js';\nexport {\n attachRunnerInstanceProviderId,\n isTerminalState,\n listActiveRunnerInstanceCountsByTemplateTx,\n listActiveRunnerInstances,\n listProvisionerTerminateIntentRowsTx,\n listProvisionerTerminateIntents,\n reapStaleRunnerInstances,\n reconcileRunnerInstances,\n reportRunnerInstances,\n} from './runner-instances.js';\nexport type {\n CreateRunnerSessionParams,\n DeleteExpiredRunnerSessionsParams,\n} from './runner-sessions.js';\nexport {createRunnerSession, deleteExpiredRunnerSessions} from './runner-sessions.js';\nexport {runnersOutbox} from './schema/outbox.js';\nexport {runnerBootstrapTokens, runnerControlSessions} from './schema/runner-control-sessions.js';\n\nexport const migrationsPath = resolve(dirname(fileURLToPath(import.meta.url)), '../../drizzle');\n"],"names":["dirname","resolve","fileURLToPath","closeDb","db","schema","createEphemeralRegistrationToken","createRunnerSessionConsumingEphemeralToken","deleteExpiredEphemeralRegistrationTokens","resolveEphemeralRegistrationTokenByHash","cancelRunnerJobs","claimPendingJobExecution","enqueueJobExecution","expireStuckJobExecutions","getWorkspaceJobCounts","isJobLeaseActive","listActiveRunningJobExecutions","listRunningJobExecutionsByRunnerInstanceTx","recordHeartbeat","releaseJobExecution","createManualRegistrationToken","listUsableManualRegistrationTokensByWorkspaceId","resolveManualRegistrationTokenByHash","revokeManualRegistrationToken","hasActiveWorkspaceProvisionerCapability","listActiveWorkspaceProvisionerCapabilitySnapshots","listStaleWorkspaceProvisionerCapabilitySnapshots","publishWorkspaceProvisionerCapabilitySnapshot","createProvisionerToken","listActiveProvisionerTokens","listUsableProvisionerTokensByWorkspaceId","resolveProvisionerTokenByHash","revokeProvisionerToken","touchProvisionerLastSeen","consumeRunnersRateLimit","pruneExpiredRunnersRateLimits","deleteExpiredReservations","deleteReservationsByIds","pollDemandAndReserve","releaseReservationUnits","assignRunnerInstances","attachRunnerInstanceProviderId","isTerminalState","listActiveRunnerInstanceCountsByTemplateTx","listActiveRunnerInstances","listProvisionerTerminateIntentRowsTx","listProvisionerTerminateIntents","reapStaleRunnerInstances","reconcileRunnerInstances","reportRunnerInstances","createRunnerSession","deleteExpiredRunnerSessions","runnersOutbox","runnerBootstrapTokens","runnerControlSessions","migrationsPath","url"],"mappings":"AAAA,SAAQA,OAAO,EAAEC,OAAO,QAAO,YAAY;AAC3C,SAAQC,aAAa,QAAO,WAAW;AAEvC,SAAQC,OAAO,EAAEC,EAAE,EAAEC,MAAM,QAAO,UAAU;AAK5C,SACEC,gCAAgC,EAChCC,0CAA0C,EAC1CC,wCAAwC,EACxCC,uCAAuC,QAClC,qCAAqC;AAM5C,SACEC,gBAAgB,EAChBC,wBAAwB,EACxBC,mBAAmB,EACnBC,wBAAwB,EACxBC,qBAAqB,EACrBC,gBAAgB,EAChBC,8BAA8B,EAC9BC,0CAA0C,EAC1CC,eAAe,EACfC,mBAAmB,QACd,sBAAsB;AAE7B,SACEC,6BAA6B,EAC7BC,+CAA+C,EAC/CC,oCAAoC,EACpCC,6BAA6B,QACxB,kCAAkC;AACzC,SACEC,uCAAuC,EACvCC,iDAAiD,EACjDC,gDAAgD,EAChDC,6CAA6C,QACxC,wCAAwC;AAE/C,SACEC,sBAAsB,EACtBC,2BAA2B,EAC3BC,wCAAwC,EACxCC,6BAA6B,EAC7BC,sBAAsB,EACtBC,wBAAwB,QACnB,0BAA0B;AACjC,SACEC,uBAAuB,EACvBC,6BAA6B,QACxB,mBAAmB;AAO1B,SACEC,yBAAyB,EACzBC,uBAAuB,EACvBC,oBAAoB,EACpBC,uBAAuB,QAClB,oBAAoB;AAC3B,SAAQC,qBAAqB,QAAO,0BAA0B;AAW9D,SACEC,8BAA8B,EAC9BC,eAAe,EACfC,0CAA0C,EAC1CC,yBAAyB,EACzBC,oCAAoC,EACpCC,+BAA+B,EAC/BC,wBAAwB,EACxBC,wBAAwB,EACxBC,qBAAqB,QAChB,wBAAwB;AAK/B,SAAQC,mBAAmB,EAAEC,2BAA2B,QAAO,uBAAuB;AACtF,SAAQC,aAAa,QAAO,qBAAqB;AACjD,SAAQC,qBAAqB,EAAEC,qBAAqB,QAAO,sCAAsC;AAEjG,OAAO,MAAMC,iBAAiBtD,QAAQD,QAAQE,cAAc,YAAYsD,GAAG,IAAI,iBAAiB"}
|
|
@@ -9,6 +9,13 @@ export interface EnqueueJobExecutionParams {
|
|
|
9
9
|
projectId: string;
|
|
10
10
|
requiredLabels: string[];
|
|
11
11
|
}
|
|
12
|
+
export declare function getWorkspaceJobCounts(params: {
|
|
13
|
+
workspaceIds: string[];
|
|
14
|
+
}): Promise<Array<{
|
|
15
|
+
workspaceId: string;
|
|
16
|
+
queued: number;
|
|
17
|
+
running: number;
|
|
18
|
+
}>>;
|
|
12
19
|
export declare function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void>;
|
|
13
20
|
export interface ClaimedJobExecution {
|
|
14
21
|
workflowRunId: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,6 +10,31 @@ import { runnersOutbox } from './schema/outbox.js';
|
|
|
10
10
|
import { pendingJobExecutions } from './schema/pending-job-executions.js';
|
|
11
11
|
import { runnerSessions } from './schema/runner-sessions.js';
|
|
12
12
|
import { runningJobExecutions } from './schema/running-job-executions.js';
|
|
13
|
+
export async function getWorkspaceJobCounts(params) {
|
|
14
|
+
const [pendingRows, runningRows] = await Promise.all([
|
|
15
|
+
db().select({
|
|
16
|
+
workspaceId: pendingJobExecutions.workspaceId,
|
|
17
|
+
count: count()
|
|
18
|
+
}).from(pendingJobExecutions).where(inArray(pendingJobExecutions.workspaceId, params.workspaceIds)).groupBy(pendingJobExecutions.workspaceId),
|
|
19
|
+
db().select({
|
|
20
|
+
workspaceId: runningJobExecutions.workspaceId,
|
|
21
|
+
count: count()
|
|
22
|
+
}).from(runningJobExecutions).where(inArray(runningJobExecutions.workspaceId, params.workspaceIds)).groupBy(runningJobExecutions.workspaceId)
|
|
23
|
+
]);
|
|
24
|
+
const queuedByWorkspace = new Map(pendingRows.map((row)=>[
|
|
25
|
+
row.workspaceId,
|
|
26
|
+
Number(row.count)
|
|
27
|
+
]));
|
|
28
|
+
const runningByWorkspace = new Map(runningRows.map((row)=>[
|
|
29
|
+
row.workspaceId,
|
|
30
|
+
Number(row.count)
|
|
31
|
+
]));
|
|
32
|
+
return params.workspaceIds.map((workspaceId)=>({
|
|
33
|
+
workspaceId,
|
|
34
|
+
queued: queuedByWorkspace.get(workspaceId) ?? 0,
|
|
35
|
+
running: runningByWorkspace.get(workspaceId) ?? 0
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
13
38
|
// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in
|
|
14
39
|
// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity
|
|
15
40
|
// at-least-once, so a unique-violation throw on a retry-after-lost-result
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/job-executions.ts"],"sourcesContent":["import {\n RUNNER_JOB_CLAIMED,\n RUNNER_JOB_LEASE_EXPIRED,\n RUNNER_JOB_QUEUED,\n type RunnersEventMap,\n type RunnerToolCapabilitiesDto,\n} from '@shipfox/api-runners-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContained,\n asc,\n count,\n desc,\n eq,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport {\n EmptyRequiredLabelsError,\n RunnerSessionExhaustedError,\n RunningJobExecutionNotFoundError,\n} from '#core/errors.js';\nimport {jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport interface EnqueueJobExecutionParams {\n workspaceId: string;\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n}\n\n// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in\n// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity\n// at-least-once, so a unique-violation throw on a retry-after-lost-result\n// would permanently fail a healthy job execution's workflow. The guard does not extend\n// past the claim: once the job execution has moved to `runners_running_jobs`, a retry\n// can reinsert an orphan pending row, which a later `claimPendingJobExecution` drops\n// via the running-execution unique constraint (onConflictDoNothing) instead of failing.\nexport async function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void> {\n const requiredLabels = [...canonicalizeLabels(params.requiredLabels)];\n if (requiredLabels.length === 0) throw new EmptyRequiredLabelsError();\n\n const enqueued = await db().transaction(async (tx) => {\n const [inserted] = await tx\n .insert(pendingJobExecutions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n projectId: params.projectId,\n requiredLabels,\n })\n .onConflictDoNothing({target: pendingJobExecutions.jobExecutionId})\n .returning({createdAt: pendingJobExecutions.createdAt});\n\n // A retry that hits the conflict inserts nothing: the first enqueue already\n // emitted the queued event (durably, in the outbox), so re-emitting would\n // only add a redundant row the subscriber coalesces away. Skip it.\n if (!inserted) return false;\n\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_QUEUED,\n payload: {\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n queuedAt: inserted.createdAt.toISOString(),\n },\n });\n return true;\n });\n\n if (enqueued) jobExecutionEnqueuedCount.add(1);\n}\n\nexport interface ClaimedJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n}\n\nexport interface ActiveRunningJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n runnerSessionId: string;\n provisionerId: string | null;\n providerRunnerId: string | null;\n requiredLabels: string[];\n runnerLabels: string[];\n startedAt: Date;\n lastHeartbeatAt: Date;\n}\n\nexport interface RunnerInstanceBoundJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport async function claimPendingJobExecution(params: {\n workspaceId: string;\n runnerSessionId: string;\n sessionLabels: string[];\n maxClaims: number | null;\n runnerSessionLivenessThrottleSeconds: number;\n}): Promise<ClaimedJobExecution | null> {\n await touchRunnerSessionLiveness({\n workspaceId: params.workspaceId,\n runnerSessionId: params.runnerSessionId,\n throttleSeconds: params.runnerSessionLivenessThrottleSeconds,\n });\n\n if (params.sessionLabels.length === 0) return null;\n\n return await db().transaction(async (tx) => {\n let provisionerId: string | null = null;\n let providerRunnerId: string | null = null;\n\n if (params.maxClaims !== null) {\n const [session] = await tx\n .select({\n maxClaims: runnerSessions.maxClaims,\n claimsUsed: runnerSessions.claimsUsed,\n revokedAt: runnerSessions.revokedAt,\n provisionerId: runnerSessions.provisionerId,\n providerRunnerId: runnerSessions.providerRunnerId,\n })\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n if (\n !session ||\n session.revokedAt ||\n session.maxClaims === null ||\n session.claimsUsed >= session.maxClaims\n ) {\n throw new RunnerSessionExhaustedError(params.runnerSessionId);\n }\n\n // Ephemeral sessions are the only capped sessions, and the DB check keeps\n // their provisioned-runner link present as a pair.\n provisionerId = session.provisionerId;\n providerRunnerId = session.providerRunnerId;\n }\n\n // `id` is a uuidv7 (time-ordered), so it is a deterministic FIFO tiebreaker\n // for rows sharing a created_at within a batch.\n const [row] = await tx\n .select()\n .from(pendingJobExecutions)\n .where(\n and(\n eq(pendingJobExecutions.workspaceId, params.workspaceId),\n arrayContained(pendingJobExecutions.requiredLabels, params.sessionLabels),\n ),\n )\n .orderBy(asc(pendingJobExecutions.createdAt), asc(pendingJobExecutions.id))\n .limit(1)\n .for('update', {skipLocked: true});\n\n if (!row) return null;\n\n await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.id, row.id));\n\n // An enqueue retry that lands after a prior claim can leave an orphan pending\n // row whose jobExecutionId is already in `runners_running_jobs`. Insert-or-skip\n // on the jobExecutionId unique constraint: when the job execution is already running\n // the insert touches no row, so we commit the orphan's deletion and return\n // null rather than let the unique violation roll the claim back into a poison\n // loop. The runner just re-polls for a real job execution.\n const inserted = await tx\n .insert(runningJobExecutions)\n .values({\n workspaceId: row.workspaceId,\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n runnerSessionId: params.runnerSessionId,\n provisionerId,\n providerRunnerId,\n requiredLabels: row.requiredLabels,\n runnerLabels: params.sessionLabels,\n })\n .onConflictDoNothing({target: runningJobExecutions.jobExecutionId})\n .returning({claimedAt: runningJobExecutions.startedAt});\n\n const claimed = inserted[0];\n if (!claimed) return null;\n\n if (params.maxClaims !== null) {\n await tx\n .update(runnerSessions)\n .set({claimsUsed: sql`${runnerSessions.claimsUsed} + 1`, updatedAt: sql`now()`})\n .where(eq(runnerSessions.id, params.runnerSessionId));\n }\n\n // The running-row insert is the runner claiming the job execution. Emit in the same tx; the\n // payload carries the row's own claim instant so a consumer records the true time,\n // not the outbox drain time.\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_CLAIMED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n claimedAt: claimed.claimedAt.toISOString(),\n },\n });\n\n return {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n };\n });\n}\n\nasync function touchRunnerSessionLiveness(params: {\n workspaceId: string;\n runnerSessionId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(runnerSessions)\n .set({updatedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.id, params.runnerSessionId),\n eq(runnerSessions.workspaceId, params.workspaceId),\n sql`${runnerSessions.updatedAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n );\n}\n\n/**\n * Releases a job execution's lease when the orchestration workflow finalizes it: deletes the\n * running-job-execution row AND any lingering pending row for the same execution, in one tx.\n * Idempotent (0-row no-op), no token scope (the workflow is authoritative), and\n * emits no event — the workflow already owns the outcome. Sweeping the pending row\n * too closes the at-least-once window where an enqueue retry left an orphan that a\n * later claim would otherwise pick up for an already-finished job execution.\n */\nexport async function releaseJobExecution(params: {jobExecutionId: string}): Promise<void> {\n await db().transaction(async (tx) => {\n // Delete pending before running to match `claimPendingJobExecution`'s lock-acquisition\n // order (it locks the pending row first, then the running row). A concurrent\n // claim picking up an orphan pending row for this same job execution would otherwise\n // deadlock against the reverse order here.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .delete(runningJobExecutions)\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\n/**\n * Reaps stale leases (bounded by `limit`), emitting one\n * `runners.job.lease_expired` event per reaped job execution.\n *\n * The cutoff is re-checked in the DELETE, not just the locking subquery, so a\n * heartbeat landing mid-call spares the live row. Each reaped execution also sweeps its\n * pending row: a failed best-effort `releaseJobExecution` would otherwise leave an orphan\n * that a later claim re-runs as an already-finished job execution.\n *\n * Locks running-then-pending, the inverse of `claimPendingJobExecution` / `releaseJobExecution`.\n * That pre-existing asymmetry opens a narrow deadlock window against a concurrent\n * claim of the same orphan-pending job execution; Postgres breaks it and the cron retries.\n */\nexport async function expireStuckJobExecutions(params: {\n thresholdSeconds: number;\n noFirstHeartbeatGraceSeconds: number;\n limit?: number;\n}): Promise<\n Array<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n }>\n> {\n const reaped = await db().transaction(async (tx) => {\n const heartbeatCutoff = sql`now() - (${params.thresholdSeconds} || ' seconds')::interval`;\n const firstHeartbeatCutoff = sql`now() - (${params.noFirstHeartbeatGraceSeconds} || ' seconds')::interval`;\n const stalePredicate = or(\n and(\n isNull(runningJobExecutions.firstHeartbeatAt),\n lte(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n lt(runningJobExecutions.startedAt, firstHeartbeatCutoff),\n ),\n and(\n or(\n isNotNull(runningJobExecutions.firstHeartbeatAt),\n gt(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n ),\n lt(runningJobExecutions.lastHeartbeatAt, heartbeatCutoff),\n ),\n );\n\n const staleIds = tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(stalePredicate)\n .orderBy(\n asc(\n sql`CASE WHEN ${runningJobExecutions.firstHeartbeatAt} IS NULL AND ${runningJobExecutions.lastHeartbeatAt} <= ${runningJobExecutions.startedAt} THEN ${runningJobExecutions.startedAt} ELSE ${runningJobExecutions.lastHeartbeatAt} END`,\n ),\n )\n .limit(params.limit ?? 100)\n .for('update', {skipLocked: true});\n\n const deleted = await tx\n .delete(runningJobExecutions)\n .where(and(inArray(runningJobExecutions.id, staleIds), stalePredicate))\n .returning({\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n });\n\n if (deleted.length === 0) return [];\n\n await tx.delete(pendingJobExecutions).where(\n inArray(\n pendingJobExecutions.jobExecutionId,\n deleted.map((row) => row.jobExecutionId),\n ),\n );\n\n await writeOutboxEvents<RunnersEventMap>(\n tx,\n runnersOutbox,\n deleted.map((row) => ({\n type: RUNNER_JOB_LEASE_EXPIRED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n },\n })),\n );\n\n return deleted;\n });\n\n if (reaped.length > 0) jobExecutionLeaseExpiredCount.add(reaped.length);\n\n return reaped;\n}\n\nexport async function getJobExecutionQueueDepth(): Promise<{\n pendingJobExecutions: number;\n runningJobExecutions: number;\n}> {\n const [pending] = await db().select({value: count()}).from(pendingJobExecutions);\n const [running] = await db().select({value: count()}).from(runningJobExecutions);\n return {\n pendingJobExecutions: pending?.value ?? 0,\n runningJobExecutions: running?.value ?? 0,\n };\n}\n\nexport async function listActiveRunningJobExecutions(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<ActiveRunningJobExecution[]> {\n return await db()\n .select({\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n projectId: runningJobExecutions.projectId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n provisionerId: runningJobExecutions.provisionerId,\n providerRunnerId: runningJobExecutions.providerRunnerId,\n requiredLabels: runningJobExecutions.requiredLabels,\n runnerLabels: runningJobExecutions.runnerLabels,\n startedAt: runningJobExecutions.startedAt,\n lastHeartbeatAt: runningJobExecutions.lastHeartbeatAt,\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n sql`${runningJobExecutions.lastHeartbeatAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(runningJobExecutions.lastHeartbeatAt), desc(runningJobExecutions.id))\n .limit(params.limit ?? 1000);\n}\n\nexport async function listRunningJobExecutionsByRunnerInstanceTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n providerRunnerIds: string[];\n },\n): Promise<RunnerInstanceBoundJobExecution[]> {\n if (params.providerRunnerIds.length === 0) return [];\n\n const duplicateRows = await tx\n .select({\n providerRunnerId: runningJobExecutions.providerRunnerId,\n count: count(),\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n inArray(runningJobExecutions.providerRunnerId, params.providerRunnerIds),\n ),\n )\n .groupBy(runningJobExecutions.providerRunnerId)\n .having(sql`count(*) > 1`);\n\n const duplicateRunnerInstanceIds = duplicateRows.flatMap((row) =>\n row.providerRunnerId ? [row.providerRunnerId] : [],\n );\n if (duplicateRunnerInstanceIds.length > 0) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: duplicateRunnerInstanceIds,\n },\n 'multiple running job executions are bound to the same provisioned runner',\n );\n }\n\n const result = await tx.execute<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date | string;\n lastHeartbeatAt: Date | string;\n cancellationRequestedAt: Date | string | null;\n }>(sql`\n SELECT DISTINCT ON (${runningJobExecutions.providerRunnerId})\n ${runningJobExecutions.workflowRunId} AS \"workflowRunId\",\n ${runningJobExecutions.workflowRunAttemptId} AS \"workflowRunAttemptId\",\n ${runningJobExecutions.jobId} AS \"jobId\",\n ${runningJobExecutions.jobExecutionId} AS \"jobExecutionId\",\n ${runningJobExecutions.providerRunnerId} AS \"providerRunnerId\",\n ${runningJobExecutions.startedAt} AS \"startedAt\",\n ${runningJobExecutions.lastHeartbeatAt} AS \"lastHeartbeatAt\",\n ${runningJobExecutions.cancellationRequestedAt} AS \"cancellationRequestedAt\"\n FROM ${runningJobExecutions}\n WHERE\n ${runningJobExecutions.workspaceId} = ${params.workspaceId}\n AND ${runningJobExecutions.provisionerId} = ${params.provisionerId}\n AND ${runningJobExecutions.providerRunnerId} IN (${sql.join(\n params.providerRunnerIds.map((providerRunnerId) => sql`${providerRunnerId}`),\n sql`, `,\n )})\n ORDER BY ${runningJobExecutions.providerRunnerId}, ${runningJobExecutions.startedAt} DESC, ${runningJobExecutions.jobExecutionId} DESC\n `);\n\n return result.rows.map((row) => ({\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n providerRunnerId: row.providerRunnerId,\n startedAt: toDate(row.startedAt),\n lastHeartbeatAt: toDate(row.lastHeartbeatAt),\n cancellationRequestedAt: row.cancellationRequestedAt\n ? toDate(row.cancellationRequestedAt)\n : null,\n }));\n}\n\nfunction toDate(value: Date | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\nexport async function isJobLeaseActive(params: {\n jobId?: string;\n jobExecutionId: string;\n runnerSessionId: string;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n params.jobId === undefined ? undefined : eq(runningJobExecutions.jobId, params.jobId),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nexport async function recordHeartbeat(params: {\n jobExecutionId: string;\n runnerSessionId: string;\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<{\n cancellationRequested: boolean;\n previousToolCapabilities: RunnerToolCapabilitiesDto | null;\n currentToolCapabilities: RunnerToolCapabilitiesDto | null;\n runningJobExecution: {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n workspaceId: string;\n runnerSessionId: string;\n };\n}> {\n const result = await db().transaction(async (tx) => {\n const updated = await tx\n .update(runningJobExecutions)\n .set({\n firstHeartbeatAt: sql`COALESCE(${runningJobExecutions.firstHeartbeatAt}, now())`,\n lastHeartbeatAt: sql`now()`,\n })\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n ),\n )\n .returning({\n cancellationRequestedAt: runningJobExecutions.cancellationRequestedAt,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n projectId: runningJobExecutions.projectId,\n workspaceId: runningJobExecutions.workspaceId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n });\n\n const row = updated[0];\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n\n const [previous] = await tx\n .select({toolCapabilities: runnerSessions.toolCapabilities})\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n const [session] = await tx\n .update(runnerSessions)\n .set({\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n updatedAt: sql`now()`,\n })\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .returning({toolCapabilities: runnerSessions.toolCapabilities});\n\n return {\n row,\n previousToolCapabilities: previous?.toolCapabilities ?? null,\n currentToolCapabilities: session?.toolCapabilities ?? null,\n };\n });\n\n const row = result.row;\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n return {\n cancellationRequested: row.cancellationRequestedAt !== null,\n previousToolCapabilities: result.previousToolCapabilities,\n currentToolCapabilities: result.currentToolCapabilities,\n runningJobExecution: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n workspaceId: row.workspaceId,\n runnerSessionId: row.runnerSessionId,\n },\n };\n}\n\nexport async function requestJobExecutionCancellation(params: {\n jobExecutionId: string;\n}): Promise<void> {\n await db()\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n}\n\nexport async function cancelRunnerJobs(params: {jobIds: string[]}): Promise<void> {\n if (params.jobIds.length === 0) return;\n\n await db().transaction(async (tx) => {\n await tx.delete(pendingJobExecutions).where(inArray(pendingJobExecutions.jobId, params.jobIds));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(inArray(runningJobExecutions.jobId, params.jobIds));\n });\n}\n"],"names":["RUNNER_JOB_CLAIMED","RUNNER_JOB_LEASE_EXPIRED","RUNNER_JOB_QUEUED","logger","writeOutboxEvent","writeOutboxEvents","canonicalizeLabels","and","arrayContained","asc","count","desc","eq","gt","inArray","isNotNull","isNull","lt","lte","or","sql","EmptyRequiredLabelsError","RunnerSessionExhaustedError","RunningJobExecutionNotFoundError","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","db","runnersOutbox","pendingJobExecutions","runnerSessions","runningJobExecutions","enqueueJobExecution","params","requiredLabels","length","enqueued","transaction","tx","inserted","insert","values","workspaceId","workflowRunId","workflowRunAttemptId","jobId","jobExecutionId","projectId","onConflictDoNothing","target","returning","createdAt","type","payload","queuedAt","toISOString","add","claimPendingJobExecution","touchRunnerSessionLiveness","runnerSessionId","throttleSeconds","runnerSessionLivenessThrottleSeconds","sessionLabels","provisionerId","providerRunnerId","maxClaims","session","select","claimsUsed","revokedAt","from","where","id","limit","for","row","orderBy","skipLocked","delete","runnerLabels","claimedAt","startedAt","claimed","update","set","updatedAt","releaseJobExecution","expireStuckJobExecutions","reaped","heartbeatCutoff","thresholdSeconds","firstHeartbeatCutoff","noFirstHeartbeatGraceSeconds","stalePredicate","firstHeartbeatAt","lastHeartbeatAt","staleIds","deleted","map","getJobExecutionQueueDepth","pending","value","running","listActiveRunningJobExecutions","windowSeconds","listRunningJobExecutionsByRunnerInstanceTx","providerRunnerIds","duplicateRows","groupBy","having","duplicateRunnerInstanceIds","flatMap","warn","result","execute","cancellationRequestedAt","join","rows","toDate","Date","isJobLeaseActive","undefined","recordHeartbeat","updated","previous","toolCapabilities","toolCapabilitiesReportedAt","previousToolCapabilities","currentToolCapabilities","cancellationRequested","runningJobExecution","requestJobExecutionCancellation","cancelRunnerJobs","jobIds"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/job-executions.ts"],"sourcesContent":["import {\n RUNNER_JOB_CLAIMED,\n RUNNER_JOB_LEASE_EXPIRED,\n RUNNER_JOB_QUEUED,\n type RunnersEventMap,\n type RunnerToolCapabilitiesDto,\n} from '@shipfox/api-runners-dto';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {writeOutboxEvent, writeOutboxEvents} from '@shipfox/node-outbox';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n arrayContained,\n asc,\n count,\n desc,\n eq,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n or,\n sql,\n} from 'drizzle-orm';\nimport {\n EmptyRequiredLabelsError,\n RunnerSessionExhaustedError,\n RunningJobExecutionNotFoundError,\n} from '#core/errors.js';\nimport {jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount} from '#metrics/instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {runnersOutbox} from './schema/outbox.js';\nimport {pendingJobExecutions} from './schema/pending-job-executions.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport interface EnqueueJobExecutionParams {\n workspaceId: string;\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n}\n\nexport async function getWorkspaceJobCounts(params: {\n workspaceIds: string[];\n}): Promise<Array<{workspaceId: string; queued: number; running: number}>> {\n const [pendingRows, runningRows] = await Promise.all([\n db()\n .select({workspaceId: pendingJobExecutions.workspaceId, count: count()})\n .from(pendingJobExecutions)\n .where(inArray(pendingJobExecutions.workspaceId, params.workspaceIds))\n .groupBy(pendingJobExecutions.workspaceId),\n db()\n .select({workspaceId: runningJobExecutions.workspaceId, count: count()})\n .from(runningJobExecutions)\n .where(inArray(runningJobExecutions.workspaceId, params.workspaceIds))\n .groupBy(runningJobExecutions.workspaceId),\n ]);\n\n const queuedByWorkspace = new Map(pendingRows.map((row) => [row.workspaceId, Number(row.count)]));\n const runningByWorkspace = new Map(\n runningRows.map((row) => [row.workspaceId, Number(row.count)]),\n );\n\n return params.workspaceIds.map((workspaceId) => ({\n workspaceId,\n queued: queuedByWorkspace.get(workspaceId) ?? 0,\n running: runningByWorkspace.get(workspaceId) ?? 0,\n }));\n}\n\n// Idempotent while the job execution is still pending: a duplicate jobExecutionId already in\n// `runners_pending_jobs` is a no-op. Temporal retries the enqueue activity\n// at-least-once, so a unique-violation throw on a retry-after-lost-result\n// would permanently fail a healthy job execution's workflow. The guard does not extend\n// past the claim: once the job execution has moved to `runners_running_jobs`, a retry\n// can reinsert an orphan pending row, which a later `claimPendingJobExecution` drops\n// via the running-execution unique constraint (onConflictDoNothing) instead of failing.\nexport async function enqueueJobExecution(params: EnqueueJobExecutionParams): Promise<void> {\n const requiredLabels = [...canonicalizeLabels(params.requiredLabels)];\n if (requiredLabels.length === 0) throw new EmptyRequiredLabelsError();\n\n const enqueued = await db().transaction(async (tx) => {\n const [inserted] = await tx\n .insert(pendingJobExecutions)\n .values({\n workspaceId: params.workspaceId,\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n projectId: params.projectId,\n requiredLabels,\n })\n .onConflictDoNothing({target: pendingJobExecutions.jobExecutionId})\n .returning({createdAt: pendingJobExecutions.createdAt});\n\n // A retry that hits the conflict inserts nothing: the first enqueue already\n // emitted the queued event (durably, in the outbox), so re-emitting would\n // only add a redundant row the subscriber coalesces away. Skip it.\n if (!inserted) return false;\n\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_QUEUED,\n payload: {\n workflowRunId: params.workflowRunId,\n workflowRunAttemptId: params.workflowRunAttemptId,\n jobId: params.jobId,\n jobExecutionId: params.jobExecutionId,\n queuedAt: inserted.createdAt.toISOString(),\n },\n });\n return true;\n });\n\n if (enqueued) jobExecutionEnqueuedCount.add(1);\n}\n\nexport interface ClaimedJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n}\n\nexport interface ActiveRunningJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n runnerSessionId: string;\n provisionerId: string | null;\n providerRunnerId: string | null;\n requiredLabels: string[];\n runnerLabels: string[];\n startedAt: Date;\n lastHeartbeatAt: Date;\n}\n\nexport interface RunnerInstanceBoundJobExecution {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date;\n lastHeartbeatAt: Date;\n cancellationRequestedAt: Date | null;\n}\n\nexport async function claimPendingJobExecution(params: {\n workspaceId: string;\n runnerSessionId: string;\n sessionLabels: string[];\n maxClaims: number | null;\n runnerSessionLivenessThrottleSeconds: number;\n}): Promise<ClaimedJobExecution | null> {\n await touchRunnerSessionLiveness({\n workspaceId: params.workspaceId,\n runnerSessionId: params.runnerSessionId,\n throttleSeconds: params.runnerSessionLivenessThrottleSeconds,\n });\n\n if (params.sessionLabels.length === 0) return null;\n\n return await db().transaction(async (tx) => {\n let provisionerId: string | null = null;\n let providerRunnerId: string | null = null;\n\n if (params.maxClaims !== null) {\n const [session] = await tx\n .select({\n maxClaims: runnerSessions.maxClaims,\n claimsUsed: runnerSessions.claimsUsed,\n revokedAt: runnerSessions.revokedAt,\n provisionerId: runnerSessions.provisionerId,\n providerRunnerId: runnerSessions.providerRunnerId,\n })\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n if (\n !session ||\n session.revokedAt ||\n session.maxClaims === null ||\n session.claimsUsed >= session.maxClaims\n ) {\n throw new RunnerSessionExhaustedError(params.runnerSessionId);\n }\n\n // Ephemeral sessions are the only capped sessions, and the DB check keeps\n // their provisioned-runner link present as a pair.\n provisionerId = session.provisionerId;\n providerRunnerId = session.providerRunnerId;\n }\n\n // `id` is a uuidv7 (time-ordered), so it is a deterministic FIFO tiebreaker\n // for rows sharing a created_at within a batch.\n const [row] = await tx\n .select()\n .from(pendingJobExecutions)\n .where(\n and(\n eq(pendingJobExecutions.workspaceId, params.workspaceId),\n arrayContained(pendingJobExecutions.requiredLabels, params.sessionLabels),\n ),\n )\n .orderBy(asc(pendingJobExecutions.createdAt), asc(pendingJobExecutions.id))\n .limit(1)\n .for('update', {skipLocked: true});\n\n if (!row) return null;\n\n await tx.delete(pendingJobExecutions).where(eq(pendingJobExecutions.id, row.id));\n\n // An enqueue retry that lands after a prior claim can leave an orphan pending\n // row whose jobExecutionId is already in `runners_running_jobs`. Insert-or-skip\n // on the jobExecutionId unique constraint: when the job execution is already running\n // the insert touches no row, so we commit the orphan's deletion and return\n // null rather than let the unique violation roll the claim back into a poison\n // loop. The runner just re-polls for a real job execution.\n const inserted = await tx\n .insert(runningJobExecutions)\n .values({\n workspaceId: row.workspaceId,\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n runnerSessionId: params.runnerSessionId,\n provisionerId,\n providerRunnerId,\n requiredLabels: row.requiredLabels,\n runnerLabels: params.sessionLabels,\n })\n .onConflictDoNothing({target: runningJobExecutions.jobExecutionId})\n .returning({claimedAt: runningJobExecutions.startedAt});\n\n const claimed = inserted[0];\n if (!claimed) return null;\n\n if (params.maxClaims !== null) {\n await tx\n .update(runnerSessions)\n .set({claimsUsed: sql`${runnerSessions.claimsUsed} + 1`, updatedAt: sql`now()`})\n .where(eq(runnerSessions.id, params.runnerSessionId));\n }\n\n // The running-row insert is the runner claiming the job execution. Emit in the same tx; the\n // payload carries the row's own claim instant so a consumer records the true time,\n // not the outbox drain time.\n await writeOutboxEvent<RunnersEventMap>(tx, runnersOutbox, {\n type: RUNNER_JOB_CLAIMED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n claimedAt: claimed.claimedAt.toISOString(),\n },\n });\n\n return {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n };\n });\n}\n\nasync function touchRunnerSessionLiveness(params: {\n workspaceId: string;\n runnerSessionId: string;\n throttleSeconds: number;\n}): Promise<void> {\n await db()\n .update(runnerSessions)\n .set({updatedAt: sql`now()`})\n .where(\n and(\n eq(runnerSessions.id, params.runnerSessionId),\n eq(runnerSessions.workspaceId, params.workspaceId),\n sql`${runnerSessions.updatedAt} < now() - (${params.throttleSeconds} || ' seconds')::interval`,\n ),\n );\n}\n\n/**\n * Releases a job execution's lease when the orchestration workflow finalizes it: deletes the\n * running-job-execution row AND any lingering pending row for the same execution, in one tx.\n * Idempotent (0-row no-op), no token scope (the workflow is authoritative), and\n * emits no event — the workflow already owns the outcome. Sweeping the pending row\n * too closes the at-least-once window where an enqueue retry left an orphan that a\n * later claim would otherwise pick up for an already-finished job execution.\n */\nexport async function releaseJobExecution(params: {jobExecutionId: string}): Promise<void> {\n await db().transaction(async (tx) => {\n // Delete pending before running to match `claimPendingJobExecution`'s lock-acquisition\n // order (it locks the pending row first, then the running row). A concurrent\n // claim picking up an orphan pending row for this same job execution would otherwise\n // deadlock against the reverse order here.\n await tx\n .delete(pendingJobExecutions)\n .where(eq(pendingJobExecutions.jobExecutionId, params.jobExecutionId));\n await tx\n .delete(runningJobExecutions)\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n });\n}\n\n/**\n * Reaps stale leases (bounded by `limit`), emitting one\n * `runners.job.lease_expired` event per reaped job execution.\n *\n * The cutoff is re-checked in the DELETE, not just the locking subquery, so a\n * heartbeat landing mid-call spares the live row. Each reaped execution also sweeps its\n * pending row: a failed best-effort `releaseJobExecution` would otherwise leave an orphan\n * that a later claim re-runs as an already-finished job execution.\n *\n * Locks running-then-pending, the inverse of `claimPendingJobExecution` / `releaseJobExecution`.\n * That pre-existing asymmetry opens a narrow deadlock window against a concurrent\n * claim of the same orphan-pending job execution; Postgres breaks it and the cron retries.\n */\nexport async function expireStuckJobExecutions(params: {\n thresholdSeconds: number;\n noFirstHeartbeatGraceSeconds: number;\n limit?: number;\n}): Promise<\n Array<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n }>\n> {\n const reaped = await db().transaction(async (tx) => {\n const heartbeatCutoff = sql`now() - (${params.thresholdSeconds} || ' seconds')::interval`;\n const firstHeartbeatCutoff = sql`now() - (${params.noFirstHeartbeatGraceSeconds} || ' seconds')::interval`;\n const stalePredicate = or(\n and(\n isNull(runningJobExecutions.firstHeartbeatAt),\n lte(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n lt(runningJobExecutions.startedAt, firstHeartbeatCutoff),\n ),\n and(\n or(\n isNotNull(runningJobExecutions.firstHeartbeatAt),\n gt(runningJobExecutions.lastHeartbeatAt, runningJobExecutions.startedAt),\n ),\n lt(runningJobExecutions.lastHeartbeatAt, heartbeatCutoff),\n ),\n );\n\n const staleIds = tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(stalePredicate)\n .orderBy(\n asc(\n sql`CASE WHEN ${runningJobExecutions.firstHeartbeatAt} IS NULL AND ${runningJobExecutions.lastHeartbeatAt} <= ${runningJobExecutions.startedAt} THEN ${runningJobExecutions.startedAt} ELSE ${runningJobExecutions.lastHeartbeatAt} END`,\n ),\n )\n .limit(params.limit ?? 100)\n .for('update', {skipLocked: true});\n\n const deleted = await tx\n .delete(runningJobExecutions)\n .where(and(inArray(runningJobExecutions.id, staleIds), stalePredicate))\n .returning({\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n });\n\n if (deleted.length === 0) return [];\n\n await tx.delete(pendingJobExecutions).where(\n inArray(\n pendingJobExecutions.jobExecutionId,\n deleted.map((row) => row.jobExecutionId),\n ),\n );\n\n await writeOutboxEvents<RunnersEventMap>(\n tx,\n runnersOutbox,\n deleted.map((row) => ({\n type: RUNNER_JOB_LEASE_EXPIRED,\n payload: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n },\n })),\n );\n\n return deleted;\n });\n\n if (reaped.length > 0) jobExecutionLeaseExpiredCount.add(reaped.length);\n\n return reaped;\n}\n\nexport async function getJobExecutionQueueDepth(): Promise<{\n pendingJobExecutions: number;\n runningJobExecutions: number;\n}> {\n const [pending] = await db().select({value: count()}).from(pendingJobExecutions);\n const [running] = await db().select({value: count()}).from(runningJobExecutions);\n return {\n pendingJobExecutions: pending?.value ?? 0,\n runningJobExecutions: running?.value ?? 0,\n };\n}\n\nexport async function listActiveRunningJobExecutions(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<ActiveRunningJobExecution[]> {\n return await db()\n .select({\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n projectId: runningJobExecutions.projectId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n provisionerId: runningJobExecutions.provisionerId,\n providerRunnerId: runningJobExecutions.providerRunnerId,\n requiredLabels: runningJobExecutions.requiredLabels,\n runnerLabels: runningJobExecutions.runnerLabels,\n startedAt: runningJobExecutions.startedAt,\n lastHeartbeatAt: runningJobExecutions.lastHeartbeatAt,\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n sql`${runningJobExecutions.lastHeartbeatAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(runningJobExecutions.lastHeartbeatAt), desc(runningJobExecutions.id))\n .limit(params.limit ?? 1000);\n}\n\nexport async function listRunningJobExecutionsByRunnerInstanceTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n providerRunnerIds: string[];\n },\n): Promise<RunnerInstanceBoundJobExecution[]> {\n if (params.providerRunnerIds.length === 0) return [];\n\n const duplicateRows = await tx\n .select({\n providerRunnerId: runningJobExecutions.providerRunnerId,\n count: count(),\n })\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n inArray(runningJobExecutions.providerRunnerId, params.providerRunnerIds),\n ),\n )\n .groupBy(runningJobExecutions.providerRunnerId)\n .having(sql`count(*) > 1`);\n\n const duplicateRunnerInstanceIds = duplicateRows.flatMap((row) =>\n row.providerRunnerId ? [row.providerRunnerId] : [],\n );\n if (duplicateRunnerInstanceIds.length > 0) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: duplicateRunnerInstanceIds,\n },\n 'multiple running job executions are bound to the same provisioned runner',\n );\n }\n\n const result = await tx.execute<{\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n providerRunnerId: string;\n startedAt: Date | string;\n lastHeartbeatAt: Date | string;\n cancellationRequestedAt: Date | string | null;\n }>(sql`\n SELECT DISTINCT ON (${runningJobExecutions.providerRunnerId})\n ${runningJobExecutions.workflowRunId} AS \"workflowRunId\",\n ${runningJobExecutions.workflowRunAttemptId} AS \"workflowRunAttemptId\",\n ${runningJobExecutions.jobId} AS \"jobId\",\n ${runningJobExecutions.jobExecutionId} AS \"jobExecutionId\",\n ${runningJobExecutions.providerRunnerId} AS \"providerRunnerId\",\n ${runningJobExecutions.startedAt} AS \"startedAt\",\n ${runningJobExecutions.lastHeartbeatAt} AS \"lastHeartbeatAt\",\n ${runningJobExecutions.cancellationRequestedAt} AS \"cancellationRequestedAt\"\n FROM ${runningJobExecutions}\n WHERE\n ${runningJobExecutions.workspaceId} = ${params.workspaceId}\n AND ${runningJobExecutions.provisionerId} = ${params.provisionerId}\n AND ${runningJobExecutions.providerRunnerId} IN (${sql.join(\n params.providerRunnerIds.map((providerRunnerId) => sql`${providerRunnerId}`),\n sql`, `,\n )})\n ORDER BY ${runningJobExecutions.providerRunnerId}, ${runningJobExecutions.startedAt} DESC, ${runningJobExecutions.jobExecutionId} DESC\n `);\n\n return result.rows.map((row) => ({\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n providerRunnerId: row.providerRunnerId,\n startedAt: toDate(row.startedAt),\n lastHeartbeatAt: toDate(row.lastHeartbeatAt),\n cancellationRequestedAt: row.cancellationRequestedAt\n ? toDate(row.cancellationRequestedAt)\n : null,\n }));\n}\n\nfunction toDate(value: Date | string): Date {\n return value instanceof Date ? value : new Date(value);\n}\n\nexport async function isJobLeaseActive(params: {\n jobId?: string;\n jobExecutionId: string;\n runnerSessionId: string;\n}): Promise<boolean> {\n const [row] = await db()\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n params.jobId === undefined ? undefined : eq(runningJobExecutions.jobId, params.jobId),\n ),\n )\n .limit(1);\n\n return row !== undefined;\n}\n\nexport async function recordHeartbeat(params: {\n jobExecutionId: string;\n runnerSessionId: string;\n toolCapabilities?: RunnerToolCapabilitiesDto | null;\n}): Promise<{\n cancellationRequested: boolean;\n previousToolCapabilities: RunnerToolCapabilitiesDto | null;\n currentToolCapabilities: RunnerToolCapabilitiesDto | null;\n runningJobExecution: {\n workflowRunId: string;\n workflowRunAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n workspaceId: string;\n runnerSessionId: string;\n };\n}> {\n const result = await db().transaction(async (tx) => {\n const updated = await tx\n .update(runningJobExecutions)\n .set({\n firstHeartbeatAt: sql`COALESCE(${runningJobExecutions.firstHeartbeatAt}, now())`,\n lastHeartbeatAt: sql`now()`,\n })\n .where(\n and(\n eq(runningJobExecutions.jobExecutionId, params.jobExecutionId),\n eq(runningJobExecutions.runnerSessionId, params.runnerSessionId),\n ),\n )\n .returning({\n cancellationRequestedAt: runningJobExecutions.cancellationRequestedAt,\n workflowRunId: runningJobExecutions.workflowRunId,\n workflowRunAttemptId: runningJobExecutions.workflowRunAttemptId,\n jobId: runningJobExecutions.jobId,\n jobExecutionId: runningJobExecutions.jobExecutionId,\n projectId: runningJobExecutions.projectId,\n workspaceId: runningJobExecutions.workspaceId,\n runnerSessionId: runningJobExecutions.runnerSessionId,\n });\n\n const row = updated[0];\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n\n const [previous] = await tx\n .select({toolCapabilities: runnerSessions.toolCapabilities})\n .from(runnerSessions)\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .limit(1)\n .for('update');\n\n const [session] = await tx\n .update(runnerSessions)\n .set({\n toolCapabilities: params.toolCapabilities ?? null,\n toolCapabilitiesReportedAt: params.toolCapabilities ? sql`now()` : null,\n updatedAt: sql`now()`,\n })\n .where(eq(runnerSessions.id, params.runnerSessionId))\n .returning({toolCapabilities: runnerSessions.toolCapabilities});\n\n return {\n row,\n previousToolCapabilities: previous?.toolCapabilities ?? null,\n currentToolCapabilities: session?.toolCapabilities ?? null,\n };\n });\n\n const row = result.row;\n if (!row) throw new RunningJobExecutionNotFoundError(params.jobExecutionId);\n return {\n cancellationRequested: row.cancellationRequestedAt !== null,\n previousToolCapabilities: result.previousToolCapabilities,\n currentToolCapabilities: result.currentToolCapabilities,\n runningJobExecution: {\n workflowRunId: row.workflowRunId,\n workflowRunAttemptId: row.workflowRunAttemptId,\n jobId: row.jobId,\n jobExecutionId: row.jobExecutionId,\n projectId: row.projectId,\n workspaceId: row.workspaceId,\n runnerSessionId: row.runnerSessionId,\n },\n };\n}\n\nexport async function requestJobExecutionCancellation(params: {\n jobExecutionId: string;\n}): Promise<void> {\n await db()\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(eq(runningJobExecutions.jobExecutionId, params.jobExecutionId));\n}\n\nexport async function cancelRunnerJobs(params: {jobIds: string[]}): Promise<void> {\n if (params.jobIds.length === 0) return;\n\n await db().transaction(async (tx) => {\n await tx.delete(pendingJobExecutions).where(inArray(pendingJobExecutions.jobId, params.jobIds));\n await tx\n .update(runningJobExecutions)\n .set({\n cancellationRequestedAt: sql`COALESCE(${runningJobExecutions.cancellationRequestedAt}, now())`,\n })\n .where(inArray(runningJobExecutions.jobId, params.jobIds));\n });\n}\n"],"names":["RUNNER_JOB_CLAIMED","RUNNER_JOB_LEASE_EXPIRED","RUNNER_JOB_QUEUED","logger","writeOutboxEvent","writeOutboxEvents","canonicalizeLabels","and","arrayContained","asc","count","desc","eq","gt","inArray","isNotNull","isNull","lt","lte","or","sql","EmptyRequiredLabelsError","RunnerSessionExhaustedError","RunningJobExecutionNotFoundError","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","db","runnersOutbox","pendingJobExecutions","runnerSessions","runningJobExecutions","getWorkspaceJobCounts","params","pendingRows","runningRows","Promise","all","select","workspaceId","from","where","workspaceIds","groupBy","queuedByWorkspace","Map","map","row","Number","runningByWorkspace","queued","get","running","enqueueJobExecution","requiredLabels","length","enqueued","transaction","tx","inserted","insert","values","workflowRunId","workflowRunAttemptId","jobId","jobExecutionId","projectId","onConflictDoNothing","target","returning","createdAt","type","payload","queuedAt","toISOString","add","claimPendingJobExecution","touchRunnerSessionLiveness","runnerSessionId","throttleSeconds","runnerSessionLivenessThrottleSeconds","sessionLabels","provisionerId","providerRunnerId","maxClaims","session","claimsUsed","revokedAt","id","limit","for","orderBy","skipLocked","delete","runnerLabels","claimedAt","startedAt","claimed","update","set","updatedAt","releaseJobExecution","expireStuckJobExecutions","reaped","heartbeatCutoff","thresholdSeconds","firstHeartbeatCutoff","noFirstHeartbeatGraceSeconds","stalePredicate","firstHeartbeatAt","lastHeartbeatAt","staleIds","deleted","getJobExecutionQueueDepth","pending","value","listActiveRunningJobExecutions","windowSeconds","listRunningJobExecutionsByRunnerInstanceTx","providerRunnerIds","duplicateRows","having","duplicateRunnerInstanceIds","flatMap","warn","result","execute","cancellationRequestedAt","join","rows","toDate","Date","isJobLeaseActive","undefined","recordHeartbeat","updated","previous","toolCapabilities","toolCapabilitiesReportedAt","previousToolCapabilities","currentToolCapabilities","cancellationRequested","runningJobExecution","requestJobExecutionCancellation","cancelRunnerJobs","jobIds"],"mappings":"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"}
|
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import type { Tx } from './db.js';
|
|
1
2
|
/** Atomically consumes reservation units by writing the immutable assignment on each runner. */
|
|
2
3
|
export declare function assignRunnerInstances(params: {
|
|
3
4
|
provisionerId: string;
|
|
4
5
|
reservationId: string;
|
|
5
6
|
runnerInstanceIds: string[];
|
|
6
7
|
}): Promise<string[]>;
|
|
8
|
+
export declare function assignRunnerInstancesTx(tx: Tx, params: {
|
|
9
|
+
provisionerId: string;
|
|
10
|
+
reservationId: string;
|
|
11
|
+
runnerInstanceIds: string[];
|
|
12
|
+
}): Promise<string[]>;
|
|
7
13
|
//# sourceMappingURL=runner-assignments.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-assignments.d.ts","sourceRoot":"","sources":["../../src/db/runner-assignments.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner-assignments.d.ts","sourceRoot":"","sources":["../../src/db/runner-assignments.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAOhC,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,CAEpB;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;CAC7B,GACA,OAAO,CAAC,MAAM,EAAE,CAAC,CAoInB"}
|
|
@@ -1,55 +1,70 @@
|
|
|
1
|
-
import { and, eq, inArray, isNull, sql } from 'drizzle-orm';
|
|
1
|
+
import { and, eq, inArray, isNull, notInArray, or, sql } from 'drizzle-orm';
|
|
2
2
|
import { ReservationExpiredError, ReservationNotFoundError, RunnerInstanceAlreadyAssignedError, RunnerInstanceNotAssignableError } from '#core/errors.js';
|
|
3
3
|
import { db } from './db.js';
|
|
4
|
+
import { terminalStates } from './runner-instances.js';
|
|
4
5
|
import { reservations } from './schema/reservations.js';
|
|
5
6
|
import { runnerControlSessions } from './schema/runner-control-sessions.js';
|
|
6
7
|
import { providerRunners } from './schema/runner-instances.js';
|
|
7
8
|
/** Atomically consumes reservation units by writing the immutable assignment on each runner. */ export async function assignRunnerInstances(params) {
|
|
9
|
+
return await db().transaction(async (tx)=>assignRunnerInstancesTx(tx, params));
|
|
10
|
+
}
|
|
11
|
+
export async function assignRunnerInstancesTx(tx, params) {
|
|
8
12
|
const runnerInstanceIds = [
|
|
9
13
|
...params.runnerInstanceIds
|
|
10
14
|
].sort();
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const runners = runnerRows.map((runner)=>({
|
|
29
|
-
...runner,
|
|
30
|
-
controlSessionId: runnerInstanceIdsWithControlSession.has(runner.id) ? runner.id : null
|
|
31
|
-
}));
|
|
32
|
-
if (runners.length !== runnerInstanceIds.length) throw new RunnerInstanceNotAssignableError(runnerInstanceIds[0] ?? '');
|
|
33
|
-
const alreadyAssigned = runners.filter((runner)=>runner.reservationId !== null);
|
|
34
|
-
if (alreadyAssigned.some((runner)=>runner.reservationId !== reservation.id)) throw new RunnerInstanceAlreadyAssignedError(alreadyAssigned[0]?.id ?? '');
|
|
35
|
-
const newRunners = runners.filter((runner)=>runner.reservationId === null);
|
|
36
|
-
const assignedCount = await tx.select({
|
|
37
|
-
count: sql`count(*)::int`
|
|
38
|
-
}).from(providerRunners).where(eq(providerRunners.reservationId, reservation.id));
|
|
39
|
-
if ((assignedCount[0]?.count ?? 0) + newRunners.length > reservation.count) throw new RunnerInstanceNotAssignableError(newRunners[0]?.id ?? '');
|
|
40
|
-
for (const runner of newRunners){
|
|
41
|
-
if (runner.state !== 'running' || !runner.providerRunnerId || !runner.controlSessionId || !reservation.requiredLabels.every((label)=>runner.labels.includes(label))) throw new RunnerInstanceNotAssignableError(runner.id);
|
|
42
|
-
}
|
|
43
|
-
if (newRunners.length > 0) {
|
|
44
|
-
await tx.update(providerRunners).set({
|
|
45
|
-
workspaceId: reservation.workspaceId,
|
|
46
|
-
reservationId: reservation.id,
|
|
47
|
-
assignedAt: sql`now()`,
|
|
48
|
-
updatedAt: sql`now()`
|
|
49
|
-
}).where(inArray(providerRunners.id, newRunners.map((runner)=>runner.id)));
|
|
50
|
-
}
|
|
15
|
+
await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${`runners_assignment:${params.provisionerId}:${params.reservationId}`}))`);
|
|
16
|
+
const runnerRows = await tx.select({
|
|
17
|
+
id: providerRunners.id,
|
|
18
|
+
reservationId: providerRunners.reservationId,
|
|
19
|
+
intendedReservationId: providerRunners.intendedReservationId,
|
|
20
|
+
workspaceId: providerRunners.workspaceId,
|
|
21
|
+
providerRunnerId: providerRunners.providerRunnerId,
|
|
22
|
+
labels: providerRunners.labels,
|
|
23
|
+
state: providerRunners.state
|
|
24
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.id, runnerInstanceIds))).for('update');
|
|
25
|
+
// The assignment outlives its short reservation row. A retry after maintenance
|
|
26
|
+
// cleanup is complete when every owned runner already carries the requested assignment.
|
|
27
|
+
if (runnerInstanceIds.length > 0 && runnerRows.length === runnerInstanceIds.length && runnerRows.every((runner)=>runner.reservationId === params.reservationId)) {
|
|
28
|
+
await tx.update(providerRunners).set({
|
|
29
|
+
intendedReservationId: null,
|
|
30
|
+
updatedAt: sql`now()`
|
|
31
|
+
}).where(and(eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.id, runnerInstanceIds)));
|
|
51
32
|
return params.runnerInstanceIds;
|
|
52
|
-
}
|
|
33
|
+
}
|
|
34
|
+
const [reservation] = await tx.select().from(reservations).where(and(eq(reservations.id, params.reservationId), eq(reservations.provisionerId, params.provisionerId))).limit(1).for('update');
|
|
35
|
+
if (!reservation) throw new ReservationNotFoundError(params.reservationId);
|
|
36
|
+
if (reservation.expiresAt <= new Date()) throw new ReservationExpiredError(params.reservationId);
|
|
37
|
+
if (runnerRows.length !== runnerInstanceIds.length) throw new RunnerInstanceNotAssignableError(runnerInstanceIds[0] ?? '');
|
|
38
|
+
const activeControlSessions = await tx.select({
|
|
39
|
+
runnerInstanceId: runnerControlSessions.runnerInstanceId
|
|
40
|
+
}).from(runnerControlSessions).where(and(inArray(runnerControlSessions.runnerInstanceId, runnerRows.map((runner)=>runner.id)), isNull(runnerControlSessions.closedAt)));
|
|
41
|
+
const runnerInstanceIdsWithControlSession = new Set(activeControlSessions.map((session)=>session.runnerInstanceId));
|
|
42
|
+
const runners = runnerRows.map((runner)=>({
|
|
43
|
+
...runner,
|
|
44
|
+
controlSessionId: runnerInstanceIdsWithControlSession.has(runner.id) ? runner.id : null
|
|
45
|
+
}));
|
|
46
|
+
const alreadyAssigned = runners.filter((runner)=>runner.reservationId !== null);
|
|
47
|
+
if (alreadyAssigned.some((runner)=>runner.reservationId !== reservation.id)) throw new RunnerInstanceAlreadyAssignedError(alreadyAssigned[0]?.id ?? '');
|
|
48
|
+
const newRunners = runners.filter((runner)=>runner.reservationId === null);
|
|
49
|
+
const assignedCount = await tx.select({
|
|
50
|
+
count: sql`count(*)::int`
|
|
51
|
+
}).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), or(and(eq(providerRunners.reservationId, reservation.id), isNull(providerRunners.reservationReleasedAt)), and(eq(providerRunners.intendedReservationId, reservation.id), notInArray(providerRunners.id, runnerInstanceIds), isNull(providerRunners.reservationReleasedAt), notInArray(providerRunners.state, [
|
|
52
|
+
...terminalStates
|
|
53
|
+
])))));
|
|
54
|
+
if ((assignedCount[0]?.count ?? 0) + newRunners.length > reservation.count) throw new RunnerInstanceNotAssignableError(newRunners[0]?.id ?? '');
|
|
55
|
+
for (const runner of newRunners){
|
|
56
|
+
if (runner.state !== 'running' || !runner.providerRunnerId || !runner.controlSessionId || !reservation.requiredLabels.every((label)=>runner.labels.includes(label))) throw new RunnerInstanceNotAssignableError(runner.id);
|
|
57
|
+
}
|
|
58
|
+
if (newRunners.length > 0) {
|
|
59
|
+
await tx.update(providerRunners).set({
|
|
60
|
+
workspaceId: reservation.workspaceId,
|
|
61
|
+
reservationId: reservation.id,
|
|
62
|
+
intendedReservationId: null,
|
|
63
|
+
assignedAt: sql`now()`,
|
|
64
|
+
updatedAt: sql`now()`
|
|
65
|
+
}).where(inArray(providerRunners.id, newRunners.map((runner)=>runner.id)));
|
|
66
|
+
}
|
|
67
|
+
return params.runnerInstanceIds;
|
|
53
68
|
}
|
|
54
69
|
|
|
55
70
|
//# sourceMappingURL=runner-assignments.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/db/runner-assignments.ts"],"sourcesContent":["import {and, eq, inArray, isNull, sql} from 'drizzle-orm';\nimport {\n ReservationExpiredError,\n ReservationNotFoundError,\n RunnerInstanceAlreadyAssignedError,\n RunnerInstanceNotAssignableError,\n} from '#core/errors.js';\nimport {db} from './db.js';\nimport {reservations} from './schema/reservations.js';\nimport {runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners} from './schema/runner-instances.js';\n\n/** Atomically consumes reservation units by writing the immutable assignment on each runner. */\nexport async function assignRunnerInstances(params: {\n provisionerId: string;\n reservationId: string;\n runnerInstanceIds: string[];\n}): Promise<string[]> {\n const runnerInstanceIds = [...params.runnerInstanceIds].sort();\n return await db().transaction(async (tx) => {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`runners_assignment:${params.provisionerId}:${params.reservationId}`}))`,\n );\n const [reservation] = await tx\n .select()\n .from(reservations)\n .where(\n and(\n eq(reservations.id, params.reservationId),\n eq(reservations.provisionerId, params.provisionerId),\n ),\n )\n .limit(1)\n .for('update');\n if (!reservation) throw new ReservationNotFoundError(params.reservationId);\n if (reservation.expiresAt <= new Date())\n throw new ReservationExpiredError(params.reservationId);\n\n const runnerRows = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n workspaceId: providerRunners.workspaceId,\n providerRunnerId: providerRunners.providerRunnerId,\n labels: providerRunners.labels,\n state: providerRunners.state,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.id, runnerInstanceIds),\n ),\n )\n .for('update');\n const activeControlSessions = await tx\n .select({runnerInstanceId: runnerControlSessions.runnerInstanceId})\n .from(runnerControlSessions)\n .where(\n and(\n inArray(\n runnerControlSessions.runnerInstanceId,\n runnerRows.map((runner) => runner.id),\n ),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n const runnerInstanceIdsWithControlSession = new Set(\n activeControlSessions.map((session) => session.runnerInstanceId),\n );\n const runners = runnerRows.map((runner) => ({\n ...runner,\n controlSessionId: runnerInstanceIdsWithControlSession.has(runner.id) ? runner.id : null,\n }));\n if (runners.length !== runnerInstanceIds.length)\n throw new RunnerInstanceNotAssignableError(runnerInstanceIds[0] ?? '');\n\n const alreadyAssigned = runners.filter((runner) => runner.reservationId !== null);\n if (alreadyAssigned.some((runner) => runner.reservationId !== reservation.id))\n throw new RunnerInstanceAlreadyAssignedError(alreadyAssigned[0]?.id ?? '');\n const newRunners = runners.filter((runner) => runner.reservationId === null);\n const assignedCount = await tx\n .select({count: sql<number>`count(*)::int`})\n .from(providerRunners)\n .where(eq(providerRunners.reservationId, reservation.id));\n if ((assignedCount[0]?.count ?? 0) + newRunners.length > reservation.count)\n throw new RunnerInstanceNotAssignableError(newRunners[0]?.id ?? '');\n for (const runner of newRunners) {\n if (\n runner.state !== 'running' ||\n !runner.providerRunnerId ||\n !runner.controlSessionId ||\n !reservation.requiredLabels.every((label) => runner.labels.includes(label))\n )\n throw new RunnerInstanceNotAssignableError(runner.id);\n }\n if (newRunners.length > 0) {\n await tx\n .update(providerRunners)\n .set({\n workspaceId: reservation.workspaceId,\n reservationId: reservation.id,\n assignedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n inArray(\n providerRunners.id,\n newRunners.map((runner) => runner.id),\n ),\n );\n }\n return params.runnerInstanceIds;\n });\n}\n"],"names":["and","eq","inArray","isNull","sql","ReservationExpiredError","ReservationNotFoundError","RunnerInstanceAlreadyAssignedError","RunnerInstanceNotAssignableError","db","reservations","runnerControlSessions","providerRunners","assignRunnerInstances","params","runnerInstanceIds","sort","transaction","tx","execute","provisionerId","reservationId","reservation","select","from","where","id","limit","for","expiresAt","Date","runnerRows","workspaceId","providerRunnerId","labels","state","activeControlSessions","runnerInstanceId","map","runner","closedAt","runnerInstanceIdsWithControlSession","Set","session","runners","controlSessionId","has","length","alreadyAssigned","filter","some","newRunners","assignedCount","count","requiredLabels","every","label","includes","update","set","assignedAt","updatedAt"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/db/runner-assignments.ts"],"sourcesContent":["import {and, eq, inArray, isNull, notInArray, or, sql} from 'drizzle-orm';\nimport {\n ReservationExpiredError,\n ReservationNotFoundError,\n RunnerInstanceAlreadyAssignedError,\n RunnerInstanceNotAssignableError,\n} from '#core/errors.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {terminalStates} from './runner-instances.js';\nimport {reservations} from './schema/reservations.js';\nimport {runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners} from './schema/runner-instances.js';\n\n/** Atomically consumes reservation units by writing the immutable assignment on each runner. */\nexport async function assignRunnerInstances(params: {\n provisionerId: string;\n reservationId: string;\n runnerInstanceIds: string[];\n}): Promise<string[]> {\n return await db().transaction(async (tx) => assignRunnerInstancesTx(tx, params));\n}\n\nexport async function assignRunnerInstancesTx(\n tx: Tx,\n params: {\n provisionerId: string;\n reservationId: string;\n runnerInstanceIds: string[];\n },\n): Promise<string[]> {\n const runnerInstanceIds = [...params.runnerInstanceIds].sort();\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`runners_assignment:${params.provisionerId}:${params.reservationId}`}))`,\n );\n const runnerRows = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n workspaceId: providerRunners.workspaceId,\n providerRunnerId: providerRunners.providerRunnerId,\n labels: providerRunners.labels,\n state: providerRunners.state,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.id, runnerInstanceIds),\n ),\n )\n .for('update');\n\n // The assignment outlives its short reservation row. A retry after maintenance\n // cleanup is complete when every owned runner already carries the requested assignment.\n if (\n runnerInstanceIds.length > 0 &&\n runnerRows.length === runnerInstanceIds.length &&\n runnerRows.every((runner) => runner.reservationId === params.reservationId)\n ) {\n await tx\n .update(providerRunners)\n .set({intendedReservationId: null, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.id, runnerInstanceIds),\n ),\n );\n return params.runnerInstanceIds;\n }\n\n const [reservation] = await tx\n .select()\n .from(reservations)\n .where(\n and(\n eq(reservations.id, params.reservationId),\n eq(reservations.provisionerId, params.provisionerId),\n ),\n )\n .limit(1)\n .for('update');\n if (!reservation) throw new ReservationNotFoundError(params.reservationId);\n if (reservation.expiresAt <= new Date()) throw new ReservationExpiredError(params.reservationId);\n if (runnerRows.length !== runnerInstanceIds.length)\n throw new RunnerInstanceNotAssignableError(runnerInstanceIds[0] ?? '');\n\n const activeControlSessions = await tx\n .select({runnerInstanceId: runnerControlSessions.runnerInstanceId})\n .from(runnerControlSessions)\n .where(\n and(\n inArray(\n runnerControlSessions.runnerInstanceId,\n runnerRows.map((runner) => runner.id),\n ),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n const runnerInstanceIdsWithControlSession = new Set(\n activeControlSessions.map((session) => session.runnerInstanceId),\n );\n const runners = runnerRows.map((runner) => ({\n ...runner,\n controlSessionId: runnerInstanceIdsWithControlSession.has(runner.id) ? runner.id : null,\n }));\n\n const alreadyAssigned = runners.filter((runner) => runner.reservationId !== null);\n if (alreadyAssigned.some((runner) => runner.reservationId !== reservation.id))\n throw new RunnerInstanceAlreadyAssignedError(alreadyAssigned[0]?.id ?? '');\n const newRunners = runners.filter((runner) => runner.reservationId === null);\n const assignedCount = await tx\n .select({count: sql<number>`count(*)::int`})\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n or(\n and(\n eq(providerRunners.reservationId, reservation.id),\n isNull(providerRunners.reservationReleasedAt),\n ),\n and(\n eq(providerRunners.intendedReservationId, reservation.id),\n notInArray(providerRunners.id, runnerInstanceIds),\n isNull(providerRunners.reservationReleasedAt),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n ),\n ),\n );\n if ((assignedCount[0]?.count ?? 0) + newRunners.length > reservation.count)\n throw new RunnerInstanceNotAssignableError(newRunners[0]?.id ?? '');\n for (const runner of newRunners) {\n if (\n runner.state !== 'running' ||\n !runner.providerRunnerId ||\n !runner.controlSessionId ||\n !reservation.requiredLabels.every((label) => runner.labels.includes(label))\n )\n throw new RunnerInstanceNotAssignableError(runner.id);\n }\n if (newRunners.length > 0) {\n await tx\n .update(providerRunners)\n .set({\n workspaceId: reservation.workspaceId,\n reservationId: reservation.id,\n intendedReservationId: null,\n assignedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n inArray(\n providerRunners.id,\n newRunners.map((runner) => runner.id),\n ),\n );\n }\n return params.runnerInstanceIds;\n}\n"],"names":["and","eq","inArray","isNull","notInArray","or","sql","ReservationExpiredError","ReservationNotFoundError","RunnerInstanceAlreadyAssignedError","RunnerInstanceNotAssignableError","db","terminalStates","reservations","runnerControlSessions","providerRunners","assignRunnerInstances","params","transaction","tx","assignRunnerInstancesTx","runnerInstanceIds","sort","execute","provisionerId","reservationId","runnerRows","select","id","intendedReservationId","workspaceId","providerRunnerId","labels","state","from","where","for","length","every","runner","update","set","updatedAt","reservation","limit","expiresAt","Date","activeControlSessions","runnerInstanceId","map","closedAt","runnerInstanceIdsWithControlSession","Set","session","runners","controlSessionId","has","alreadyAssigned","filter","some","newRunners","assignedCount","count","reservationReleasedAt","requiredLabels","label","includes","assignedAt"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../src/db/runner-instances.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAC,cAAc,EAAE,mBAAmB,EAAC,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAEhC,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../src/db/runner-instances.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAC,cAAc,EAAE,mBAAmB,EAAC,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAC,EAAE,EAAC,MAAM,SAAS,CAAC;AAEhC,OAAO,EAEL,KAAK,+BAA+B,EACrC,MAAM,qBAAqB,CAAC;AAS7B,eAAO,MAAM,cAAc,8CAIwB,CAAC;AACpD,eAAO,MAAM,YAAY,8CAI0B,CAAC;AACpD,eAAO,MAAM,qBAAqB,kCAG/B,CAAC;AAEJ,MAAM,MAAM,mCAAmC,GAAG,eAAe,CAAC;AAElE,MAAM,WAAW,6BAA6B;IAC5C,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,mCAAmC,CAAC;CAC7C;AAED,MAAM,WAAW,iCAAiC;IAChD,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;IAC9C,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,yBAAyB;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,IAAI,CAAC;CAClB;AAED,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,yBAAyB,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,yBAAyB,EAAE,MAAM,EAAE,CAAC;IACpC,qBAAqB,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,gCAAgC;IAC/C,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,oCAAoC,EAAE,GAAG,CAAC,MAAM,EAAE,+BAA+B,CAAC,CAAC;IACnF,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,8BAA8B;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,wBAAsB,8BAA8B,CAAC,MAAM,EAAE;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,OAAO,CAAC,CAcnB;AAiBD,wBAAsB,qBAAqB,CAAC,MAAM,EAAE,2BAA2B,GAAG,OAAO,CAAC;IACxF,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,uBAAuB,EAAE,6BAA6B,EAAE,CAAC;CAC1D,CAAC,CA2ED;AAED,wBAAsB,0CAA0C,CAC9D,EAAE,EAAE,EAAE,EACN,MAAM,EAAE;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,MAAM,CAAA;CAAC,GACnD,OAAO,CAAC,iCAAiC,EAAE,CAAC,CAuB9C;AAED,wBAAsB,yBAAyB,CAAC,MAAM,EAAE;IACtD,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAe5B;AAED,wBAAsB,+BAA+B,CAAC,MAAM,EAAE;IAC5D,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAKpB;AAED,wBAAsB,oCAAoC,CACxD,EAAE,EAAE,EAAE,EACN,MAAM,EAAE;IACN,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;CACf,GACA,OAAO,CAAC,6BAA6B,EAAE,CAAC,CAsB1C;AAqFD,wBAAsB,wBAAwB,CAC5C,MAAM,EAAE,8BAA8B,GACrC,OAAO,CAAC,gCAAgC,CAAC,CAqG3C;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE;IACrD,gBAAgB,EAAE,MAAM,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,8BAA8B,CAAC,CA4D1C;AAkcD,wBAAgB,eAAe,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAEnE"}
|