@shipfox/api-runners 12.3.0 → 12.4.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.
Files changed (134) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +22 -0
  3. package/dist/config.d.ts +1 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +9 -2
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/demand.d.ts +4 -2
  8. package/dist/core/demand.d.ts.map +1 -1
  9. package/dist/core/demand.js +22 -6
  10. package/dist/core/demand.js.map +1 -1
  11. package/dist/core/entities/reservation.d.ts +1 -0
  12. package/dist/core/entities/reservation.d.ts.map +1 -1
  13. package/dist/core/entities/reservation.js.map +1 -1
  14. package/dist/core/entities/runner-instance.d.ts +3 -0
  15. package/dist/core/entities/runner-instance.d.ts.map +1 -1
  16. package/dist/core/entities/runner-instance.js.map +1 -1
  17. package/dist/core/runner-activation.d.ts +4 -1
  18. package/dist/core/runner-activation.d.ts.map +1 -1
  19. package/dist/core/runner-activation.js +32 -3
  20. package/dist/core/runner-activation.js.map +1 -1
  21. package/dist/core/runner-control-sessions.d.ts +8 -4
  22. package/dist/core/runner-control-sessions.d.ts.map +1 -1
  23. package/dist/core/runner-control-sessions.js +55 -9
  24. package/dist/core/runner-control-sessions.js.map +1 -1
  25. package/dist/core/runner-instances.d.ts +1 -0
  26. package/dist/core/runner-instances.d.ts.map +1 -1
  27. package/dist/core/runner-instances.js +1 -0
  28. package/dist/core/runner-instances.js.map +1 -1
  29. package/dist/db/db.d.ts +68 -0
  30. package/dist/db/db.d.ts.map +1 -1
  31. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
  32. package/dist/db/ephemeral-registration-tokens.js +1 -1
  33. package/dist/db/ephemeral-registration-tokens.js.map +1 -1
  34. package/dist/db/reservation-locks.d.ts +6 -0
  35. package/dist/db/reservation-locks.d.ts.map +1 -0
  36. package/dist/db/reservation-locks.js +15 -0
  37. package/dist/db/reservation-locks.js.map +1 -0
  38. package/dist/db/reservations.d.ts +17 -3
  39. package/dist/db/reservations.d.ts.map +1 -1
  40. package/dist/db/reservations.js +246 -51
  41. package/dist/db/reservations.js.map +1 -1
  42. package/dist/db/runner-assignments.d.ts +17 -0
  43. package/dist/db/runner-assignments.d.ts.map +1 -1
  44. package/dist/db/runner-assignments.js +103 -8
  45. package/dist/db/runner-assignments.js.map +1 -1
  46. package/dist/db/runner-instances.d.ts +2 -2
  47. package/dist/db/runner-instances.d.ts.map +1 -1
  48. package/dist/db/runner-instances.js +124 -24
  49. package/dist/db/runner-instances.js.map +1 -1
  50. package/dist/db/runner-states.d.ts +2 -0
  51. package/dist/db/runner-states.d.ts.map +1 -0
  52. package/dist/db/runner-states.js +7 -0
  53. package/dist/db/runner-states.js.map +1 -0
  54. package/dist/db/schema/reservations.d.ts +18 -0
  55. package/dist/db/schema/reservations.d.ts.map +1 -1
  56. package/dist/db/schema/reservations.js +7 -1
  57. package/dist/db/schema/reservations.js.map +1 -1
  58. package/dist/db/schema/runner-instances.d.ts +18 -0
  59. package/dist/db/schema/runner-instances.d.ts.map +1 -1
  60. package/dist/db/schema/runner-instances.js +8 -0
  61. package/dist/db/schema/runner-instances.js.map +1 -1
  62. package/dist/metrics/index.d.ts +2 -2
  63. package/dist/metrics/index.d.ts.map +1 -1
  64. package/dist/metrics/index.js +1 -1
  65. package/dist/metrics/index.js.map +1 -1
  66. package/dist/metrics/instance.d.ts +24 -2
  67. package/dist/metrics/instance.d.ts.map +1 -1
  68. package/dist/metrics/instance.js +23 -0
  69. package/dist/metrics/instance.js.map +1 -1
  70. package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
  71. package/dist/presentation/dto/poll-demand.js +3 -0
  72. package/dist/presentation/dto/poll-demand.js.map +1 -1
  73. package/dist/presentation/dto/runner-instances.d.ts +4 -1
  74. package/dist/presentation/dto/runner-instances.d.ts.map +1 -1
  75. package/dist/presentation/dto/runner-instances.js +4 -1
  76. package/dist/presentation/dto/runner-instances.js.map +1 -1
  77. package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -1
  78. package/dist/presentation/routes/assign-runner-instances.js +3 -3
  79. package/dist/presentation/routes/assign-runner-instances.js.map +1 -1
  80. package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
  81. package/dist/presentation/routes/poll-demand.js +1 -0
  82. package/dist/presentation/routes/poll-demand.js.map +1 -1
  83. package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -1
  84. package/dist/presentation/routes/reconcile-runner-instances.js +4 -2
  85. package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -1
  86. package/dist/presentation/routes/runner-enrollment.d.ts +4 -1
  87. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
  88. package/dist/presentation/routes/runner-enrollment.js +11 -6
  89. package/dist/presentation/routes/runner-enrollment.js.map +1 -1
  90. package/dist/tsconfig.test.tsbuildinfo +1 -1
  91. package/drizzle/0005_previous_lenny_balinger.sql +5 -0
  92. package/drizzle/meta/0005_snapshot.json +2220 -0
  93. package/drizzle/meta/_journal.json +7 -0
  94. package/package.json +2 -2
  95. package/src/config.test.ts +22 -0
  96. package/src/config.ts +15 -2
  97. package/src/core/demand.test.ts +192 -3
  98. package/src/core/demand.ts +44 -4
  99. package/src/core/entities/reservation.ts +1 -0
  100. package/src/core/entities/runner-instance.ts +4 -0
  101. package/src/core/runner-activation.ts +48 -2
  102. package/src/core/runner-control-sessions.test.ts +64 -3
  103. package/src/core/runner-control-sessions.ts +62 -9
  104. package/src/core/runner-instances.test.ts +19 -0
  105. package/src/core/runner-instances.ts +2 -0
  106. package/src/core/runner-sessions.test.ts +121 -1
  107. package/src/db/ephemeral-registration-tokens.test.ts +20 -1
  108. package/src/db/ephemeral-registration-tokens.ts +1 -0
  109. package/src/db/reservation-locks.ts +22 -0
  110. package/src/db/reservations.test.ts +733 -22
  111. package/src/db/reservations.ts +408 -144
  112. package/src/db/runner-assignments.test.ts +105 -1
  113. package/src/db/runner-assignments.ts +178 -9
  114. package/src/db/runner-instances.test.ts +265 -2
  115. package/src/db/runner-instances.ts +215 -55
  116. package/src/db/runner-states.ts +7 -0
  117. package/src/db/schema/reservations.ts +5 -1
  118. package/src/db/schema/runner-instances.ts +9 -0
  119. package/src/metrics/index.ts +10 -1
  120. package/src/metrics/instance.ts +59 -2
  121. package/src/metrics/service.test.ts +8 -1
  122. package/src/presentation/dto/poll-demand.ts +3 -0
  123. package/src/presentation/dto/runner-instances.ts +8 -1
  124. package/src/presentation/routes/assign-runner-instances.ts +6 -2
  125. package/src/presentation/routes/late-runner-enrollment.test.ts +219 -2
  126. package/src/presentation/routes/poll-demand.test.ts +56 -0
  127. package/src/presentation/routes/poll-demand.ts +1 -0
  128. package/src/presentation/routes/reconcile-runner-instances.test.ts +34 -2
  129. package/src/presentation/routes/reconcile-runner-instances.ts +7 -1
  130. package/src/presentation/routes/runner-enrollment.test.ts +316 -3
  131. package/src/presentation/routes/runner-enrollment.ts +8 -5
  132. package/test/factories/reservation.ts +2 -0
  133. package/test/factories/runner-instance.ts +6 -0
  134. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,10 +1,15 @@
1
1
  import { logger } from '@shipfox/node-opentelemetry';
2
2
  import { and, asc, desc, eq, exists, gt, inArray, isNotNull, isNull, lt, notExists, notInArray, or, sql } from 'drizzle-orm';
3
3
  import { alias } from 'drizzle-orm/pg-core';
4
+ import { config } from '#config.js';
4
5
  import { sanitizeRunnerLabels } from '#core/runner-labels.js';
6
+ import { recordRunnerReservationCapacityFailure } from '#metrics/index.js';
5
7
  import { db } from './db.js';
6
8
  import { listRunningJobExecutionsByRunnerInstanceTx } from './job-executions.js';
9
+ import { lockRunnerReservationAdvisoryKeysTx } from './reservation-locks.js';
7
10
  import { releaseReservationUnits } from './reservations.js';
11
+ import { validateRunnerReservationCapacityTx } from './runner-assignments.js';
12
+ import { terminalStates } from './runner-states.js';
8
13
  import { ephemeralRegistrationTokens } from './schema/ephemeral-registration-tokens.js';
9
14
  import { provisionerTokens } from './schema/provisioner-tokens.js';
10
15
  import { reservations } from './schema/reservations.js';
@@ -12,11 +17,6 @@ import { runnerControlSessions } from './schema/runner-control-sessions.js';
12
17
  import { providerRunners, toRunnerInstance } from './schema/runner-instances.js';
13
18
  import { runnerSessions } from './schema/runner-sessions.js';
14
19
  import { runningJobExecutions } from './schema/running-job-executions.js';
15
- export const terminalStates = [
16
- 'stopped',
17
- 'failed',
18
- 'terminated'
19
- ];
20
20
  export const activeStates = [
21
21
  'starting',
22
22
  'running',
@@ -51,8 +51,9 @@ export async function reportRunnerInstances(params) {
51
51
  await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`);
52
52
  }
53
53
  const events = await hydrateRunnerSessionIdsFromConsumedTokens(tx, params, aggregatedEvents);
54
- const terminateIntentsHonored = await listTerminateIntentsHonoredByTerminatedReportsTx(tx, params, events);
55
- const values = events.map((event)=>({
54
+ const reservationSafeEvents = await guardReportedReservationIdsTx(tx, params, events);
55
+ const terminateIntentsHonored = await listTerminateIntentsHonoredByTerminatedReportsTx(tx, params, reservationSafeEvents);
56
+ const values = reservationSafeEvents.map((event)=>({
56
57
  workspaceId: params.workspaceId,
57
58
  provisionerId: params.provisionerId,
58
59
  providerRunnerId: event.providerRunnerId,
@@ -101,14 +102,92 @@ export async function reportRunnerInstances(params) {
101
102
  OR ${providerRunnerMilestoneUpdateCondition()}
102
103
  `
103
104
  });
104
- const reservationsReleased = hasTerminalEvent ? await releaseTerminalRunnerInstanceReservations(tx, params, events) : 0;
105
+ const reservationsReleased = hasTerminalEvent ? await releaseTerminalRunnerInstanceReservations(tx, params, reservationSafeEvents) : 0;
105
106
  return {
106
- accepted: events.length,
107
+ accepted: reservationSafeEvents.length,
107
108
  reservationsReleased,
108
109
  terminateIntentsHonored
109
110
  };
110
111
  });
111
112
  }
113
+ async function guardReportedReservationIdsTx(tx, params, events) {
114
+ const reservationIds = [
115
+ ...new Set(events.flatMap((event)=>event.reservationId ? [
116
+ event.reservationId
117
+ ] : []))
118
+ ].sort();
119
+ if (reservationIds.length === 0) return events;
120
+ await lockRunnerReservationAdvisoryKeysTx(tx, {
121
+ provisionerId: params.provisionerId,
122
+ reservationIds
123
+ });
124
+ const providerRunnerIds = events.map((event)=>event.providerRunnerId);
125
+ const existingRows = await tx.select({
126
+ providerRunnerId: providerRunners.providerRunnerId,
127
+ reservationId: providerRunners.reservationId,
128
+ intendedReservationId: providerRunners.intendedReservationId,
129
+ reservationReleasedAt: providerRunners.reservationReleasedAt
130
+ }).from(providerRunners).where(and(eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.providerRunnerId, providerRunnerIds))).for('update');
131
+ const existingByProviderRunnerId = new Map(existingRows.flatMap((row)=>row.providerRunnerId ? [
132
+ [
133
+ row.providerRunnerId,
134
+ row
135
+ ]
136
+ ] : []));
137
+ const candidateReservationByProviderRunnerId = new Map();
138
+ for (const event of events){
139
+ if (!event.reservationId) continue;
140
+ if (isTerminalState(event.state)) continue;
141
+ const existing = existingByProviderRunnerId.get(event.providerRunnerId);
142
+ if (existing?.reservationId || existing?.intendedReservationId === event.reservationId) continue;
143
+ if (existing?.intendedReservationId || existing?.reservationReleasedAt) continue;
144
+ candidateReservationByProviderRunnerId.set(event.providerRunnerId, event.reservationId);
145
+ }
146
+ const validation = await validateRunnerReservationCapacityTx(tx, {
147
+ provisionerId: params.provisionerId,
148
+ requests: [
149
+ ...candidateReservationByProviderRunnerId.values()
150
+ ].map((reservationId)=>({
151
+ reservationId,
152
+ count: 1
153
+ }))
154
+ }, {
155
+ advisoryLocksHeld: true
156
+ });
157
+ for (const { reason, count } of validation.unavailableByReservation.values())recordRunnerReservationCapacityFailure(reason, count);
158
+ const remainingAcceptedByReservation = new Map(validation.acceptedByReservation);
159
+ return events.map((event)=>{
160
+ const existing = existingByProviderRunnerId.get(event.providerRunnerId);
161
+ const reservationId = candidateReservationByProviderRunnerId.get(event.providerRunnerId);
162
+ if (!reservationId) {
163
+ if (event.reservationId && isTerminalState(event.state)) {
164
+ // Terminal cleanup releases the IDs stored on the projection row. An arbitrary
165
+ // terminal report must not consume reservation capacity during that cleanup.
166
+ const matchesExistingReservation = existing !== undefined && (existing.reservationId === event.reservationId || existing.intendedReservationId === event.reservationId);
167
+ if (!matchesExistingReservation) return {
168
+ ...event,
169
+ reservationId: null
170
+ };
171
+ }
172
+ if (event.reservationId && existing?.intendedReservationId && existing.intendedReservationId !== event.reservationId) return {
173
+ ...event,
174
+ reservationId: null
175
+ };
176
+ if (event.reservationId && existing?.reservationReleasedAt) return {
177
+ ...event,
178
+ reservationId: null
179
+ };
180
+ return event;
181
+ }
182
+ const remaining = remainingAcceptedByReservation.get(reservationId) ?? 0;
183
+ if (remaining === 0) return {
184
+ ...event,
185
+ reservationId: null
186
+ };
187
+ remainingAcceptedByReservation.set(reservationId, remaining - 1);
188
+ return event;
189
+ });
190
+ }
112
191
  export async function listActiveRunnerInstanceCountsByTemplateTx(tx, params) {
113
192
  const rows = await tx.select({
114
193
  templateKey: providerRunners.templateKey,
@@ -153,21 +232,47 @@ export async function listProvisionerTerminateIntentRowsTx(tx, params) {
153
232
  returnedCount: returnedRows.length
154
233
  }, 'provisioner terminate intents truncated by poll-demand limit');
155
234
  }
156
- return returnedRows.flatMap((row)=>row.providerRunnerId ? [
157
- {
158
- ...row,
159
- providerRunnerId: row.providerRunnerId
160
- }
235
+ const activationTimeoutRunnerIds = returnedRows.flatMap((row)=>row.reason === 'activation-timeout' && row.providerRunnerId ? [
236
+ row.providerRunnerId
161
237
  ] : []);
238
+ if (activationTimeoutRunnerIds.length > 0) {
239
+ await tx.update(providerRunners).set({
240
+ reservationReleasedAt: sql`now()`,
241
+ updatedAt: sql`now()`
242
+ }).where(and(eq(providerRunners.workspaceId, params.workspaceId), eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.providerRunnerId, activationTimeoutRunnerIds), isNull(providerRunners.reservationReleasedAt)));
243
+ }
244
+ return returnedRows.flatMap((row)=>toRunnerInstanceTerminateIntent(row));
245
+ }
246
+ function toRunnerInstanceTerminateIntent(row) {
247
+ if (!row.providerRunnerId) return [];
248
+ return [
249
+ {
250
+ providerRunnerId: row.providerRunnerId,
251
+ reason: row.reason,
252
+ ...row.reason === 'activation-timeout' && row.activationTimeoutRetry ? {
253
+ activationTimeoutRetry: true
254
+ } : {}
255
+ }
256
+ ];
162
257
  }
163
258
  function provisionerTerminateIntentsQuery(tx, params) {
164
259
  const newerRunningJobExecutions = alias(runningJobExecutions, 'newer_running_jobs');
260
+ const latestCancelledJob = exists(tx.select({
261
+ id: runningJobExecutions.id
262
+ }).from(runningJobExecutions).where(and(eq(runningJobExecutions.workspaceId, params.workspaceId), eq(runningJobExecutions.provisionerId, params.provisionerId), eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId), isNotNull(runningJobExecutions.cancellationRequestedAt), notExists(tx.select({
263
+ id: newerRunningJobExecutions.id
264
+ }).from(newerRunningJobExecutions).where(and(eq(newerRunningJobExecutions.workspaceId, runningJobExecutions.workspaceId), eq(newerRunningJobExecutions.provisionerId, runningJobExecutions.provisionerId), eq(newerRunningJobExecutions.providerRunnerId, runningJobExecutions.providerRunnerId), or(gt(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt), and(eq(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt), gt(newerRunningJobExecutions.jobExecutionId, runningJobExecutions.jobExecutionId)))))))));
265
+ const activationTimeout = and(eq(providerRunners.launchKind, 'demand'), isNull(providerRunners.runnerSessionId), lt(providerRunners.createdAt, sql`now() - (${config.RUNNER_DEMAND_ACTIVATION_TIMEOUT_SECONDS} || ' seconds')::interval`), notExists(tx.select({
266
+ id: reservations.id
267
+ }).from(reservations).where(and(or(eq(reservations.id, providerRunners.reservationId), eq(reservations.id, providerRunners.intendedReservationId)), eq(reservations.workspaceId, params.workspaceId), eq(reservations.provisionerId, params.provisionerId), gt(reservations.expiresAt, sql`now()`)))));
165
268
  return tx.select({
166
269
  providerRunnerId: providerRunners.providerRunnerId,
167
- reason: sql`'job-cancelled'`
168
- }).from(runningJobExecutions).innerJoin(providerRunners, and(eq(providerRunners.workspaceId, runningJobExecutions.workspaceId), eq(providerRunners.provisionerId, runningJobExecutions.provisionerId), eq(providerRunners.providerRunnerId, runningJobExecutions.providerRunnerId))).where(and(eq(runningJobExecutions.workspaceId, params.workspaceId), eq(runningJobExecutions.provisionerId, params.provisionerId), isNotNull(providerRunners.providerRunnerId), isNotNull(runningJobExecutions.cancellationRequestedAt), inArray(providerRunners.state, activeStates), params.providerRunnerIds && params.providerRunnerIds.length > 0 ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds) : undefined, notExists(tx.select({
169
- id: newerRunningJobExecutions.id
170
- }).from(newerRunningJobExecutions).where(and(eq(newerRunningJobExecutions.workspaceId, runningJobExecutions.workspaceId), eq(newerRunningJobExecutions.provisionerId, runningJobExecutions.provisionerId), eq(newerRunningJobExecutions.providerRunnerId, runningJobExecutions.providerRunnerId), or(gt(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt), and(eq(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt), gt(newerRunningJobExecutions.jobExecutionId, runningJobExecutions.jobExecutionId)))))))).groupBy(providerRunners.providerRunnerId);
270
+ activationTimeoutRetry: sql`${providerRunners.reservationReleasedAt} is not null`,
271
+ reason: sql`case
272
+ when ${activationTimeout} then 'activation-timeout'
273
+ else 'job-cancelled'
274
+ end`
275
+ }).from(providerRunners).where(and(eq(providerRunners.workspaceId, params.workspaceId), eq(providerRunners.provisionerId, params.provisionerId), isNotNull(providerRunners.providerRunnerId), inArray(providerRunners.state, activeStates), params.providerRunnerIds && params.providerRunnerIds.length > 0 ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds) : undefined, or(latestCancelledJob, activationTimeout)));
171
276
  }
172
277
  async function listTerminateIntentsHonoredByTerminatedReportsTx(tx, params, events) {
173
278
  if (!params.workspaceId) return [];
@@ -180,12 +285,7 @@ async function listTerminateIntentsHonoredByTerminatedReportsTx(tx, params, even
180
285
  provisionerId: params.provisionerId,
181
286
  providerRunnerIds: terminatedRunnerInstanceIds
182
287
  }).orderBy(asc(providerRunners.providerRunnerId));
183
- return rows.flatMap((row)=>row.providerRunnerId ? [
184
- {
185
- ...row,
186
- providerRunnerId: row.providerRunnerId
187
- }
188
- ] : []);
288
+ return rows.flatMap((row)=>toRunnerInstanceTerminateIntent(row));
189
289
  }
190
290
  export async function reconcileRunnerInstances(params) {
191
291
  const observedRunnerInstanceIds = [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/db/runner-instances.ts"],"sourcesContent":["import {logger} from '@shipfox/node-opentelemetry';\nimport {\n and,\n asc,\n desc,\n eq,\n exists,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n notExists,\n notInArray,\n or,\n type SQL,\n sql,\n} from 'drizzle-orm';\nimport {alias} from 'drizzle-orm/pg-core';\nimport type {RunnerInstance, RunnerInstanceState} from '#core/entities/runner-instance.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {\n listRunningJobExecutionsByRunnerInstanceTx,\n type RunnerInstanceBoundJobExecution,\n} from './job-executions.js';\nimport {releaseReservationUnits} from './reservations.js';\nimport {ephemeralRegistrationTokens} from './schema/ephemeral-registration-tokens.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\nimport {runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners, toRunnerInstance} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport const terminalStates = [\n 'stopped',\n 'failed',\n 'terminated',\n] as const satisfies readonly RunnerInstanceState[];\nexport const activeStates = [\n 'starting',\n 'running',\n 'stopping',\n] as const satisfies readonly RunnerInstanceState[];\nexport const divergenceCountStates = ['starting', 'running'] as const satisfies readonly Extract<\n RunnerInstanceState,\n 'starting' | 'running'\n>[];\n\nexport type RunnerInstanceTerminateIntentReason = 'job-cancelled';\n\nexport interface RunnerInstanceTerminateIntent {\n providerRunnerId: string;\n reason: RunnerInstanceTerminateIntentReason;\n}\n\nexport interface ActiveRunnerInstanceTemplateCount {\n templateKey: string;\n state: (typeof divergenceCountStates)[number];\n count: number;\n}\n\nexport interface RunnerInstanceReportEvent {\n providerRunnerId: string;\n reservationId: string | null;\n templateKey: string | null;\n labels: string[];\n state: RunnerInstanceState;\n reason: string | null;\n runnerSessionId: string | null;\n providerKind: string | null;\n reportedAt: Date;\n}\n\nexport interface ReportRunnerInstancesParams {\n scope: 'installation' | 'workspace';\n workspaceId: string | null;\n provisionerId: string;\n events: RunnerInstanceReportEvent[];\n}\n\nexport interface ReconcileRunnerInstancesParams {\n workspaceId: string | null;\n provisionerId: string;\n observedRunnerInstanceIds: string[];\n terminateGraceSeconds: number;\n}\n\nexport interface ReconcileRunnerInstancesDbResult {\n observedRows: RunnerInstance[];\n boundJobExecutionsByRunnerInstanceId: Map<string, RunnerInstanceBoundJobExecution>;\n absentIds: string[];\n reservationsReleased: number;\n}\n\nexport interface ReapStaleRunnerInstancesResult {\n reaped: number;\n reservationsReleased: number;\n}\n\nexport async function attachRunnerInstanceProviderId(params: {\n runnerInstanceId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n const updated = await db()\n .update(providerRunners)\n .set({providerRunnerId: params.providerRunnerId, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.providerRunnerId),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({id: providerRunners.id});\n return updated.length === 1;\n}\n\ninterface RunnerInstanceReportRow extends RunnerInstanceReportEvent {\n startedAt: Date | null;\n stoppingAt: Date | null;\n stoppedAt: Date | null;\n failedAt: Date | null;\n terminatedAt: Date | null;\n}\n\ntype RunnerInstanceMilestoneColumn =\n | typeof providerRunners.startedAt\n | typeof providerRunners.stoppingAt\n | typeof providerRunners.stoppedAt\n | typeof providerRunners.failedAt\n | typeof providerRunners.terminatedAt;\n\nexport async function reportRunnerInstances(params: ReportRunnerInstancesParams): Promise<{\n accepted: number;\n reservationsReleased: number;\n terminateIntentsHonored: RunnerInstanceTerminateIntent[];\n}> {\n if (params.events.length === 0)\n return {accepted: 0, reservationsReleased: 0, terminateIntentsHonored: []};\n\n return await db().transaction(async (tx) => {\n const receivedAt = new Date();\n const aggregatedEvents = aggregateEvents(params.events, receivedAt);\n const hasTerminalEvent = aggregatedEvents.some((event) => isTerminalState(event.state));\n\n if (hasTerminalEvent) {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`,\n );\n }\n\n const events = await hydrateRunnerSessionIdsFromConsumedTokens(tx, params, aggregatedEvents);\n const terminateIntentsHonored = await listTerminateIntentsHonoredByTerminatedReportsTx(\n tx,\n params,\n events,\n );\n\n const values = events.map((event) => ({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerId: event.providerRunnerId,\n reservationId: event.reservationId,\n templateKey: event.templateKey,\n labels: sanitizeRunnerLabels(event.labels, {\n scope: params.scope,\n logLevel: 'debug',\n source: 'runner instance report',\n }),\n state: event.state,\n reason: event.reason,\n runnerSessionId: event.runnerSessionId,\n providerKind: event.providerKind,\n reportedAt: event.reportedAt > receivedAt ? receivedAt : event.reportedAt,\n startedAt: event.startedAt,\n stoppingAt: event.stoppingAt,\n stoppedAt: event.stoppedAt,\n failedAt: event.failedAt,\n terminatedAt: event.terminatedAt,\n }));\n\n await tx\n .insert(providerRunners)\n .values(values)\n .onConflictDoUpdate({\n target: [providerRunners.provisionerId, providerRunners.providerRunnerId],\n targetWhere: isNotNull(providerRunners.providerRunnerId),\n set: {\n reservationId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(${providerRunners.reservationId}, excluded.reservation_id) ELSE ${providerRunners.reservationId} END`,\n templateKey: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.template_key, ${providerRunners.templateKey}) ELSE ${providerRunners.templateKey} END`,\n labels: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.labels ELSE ${providerRunners.labels} END`,\n state: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.state ELSE ${providerRunners.state} END`,\n reason: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reason ELSE ${providerRunners.reason} END`,\n runnerSessionId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(${providerRunners.runnerSessionId}, excluded.runner_session_id) ELSE ${providerRunners.runnerSessionId} END`,\n providerKind: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.provider_kind, ${providerRunners.providerKind}) ELSE ${providerRunners.providerKind} END`,\n reportedAt: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reported_at ELSE ${providerRunners.reportedAt} END`,\n startedAt: firstObservedAt(providerRunners.startedAt, sql`excluded.started_at`),\n stoppingAt: firstObservedAt(providerRunners.stoppingAt, sql`excluded.stopping_at`),\n stoppedAt: firstObservedAt(providerRunners.stoppedAt, sql`excluded.stopped_at`),\n failedAt: firstObservedAt(providerRunners.failedAt, sql`excluded.failed_at`),\n terminatedAt: firstObservedAt(providerRunners.terminatedAt, sql`excluded.terminated_at`),\n updatedAt: sql`now()`,\n },\n setWhere: sql`\n ${providerRunnerProjectionUpdateCondition()}\n OR ${providerRunnerMilestoneUpdateCondition()}\n `,\n });\n\n const reservationsReleased = hasTerminalEvent\n ? await releaseTerminalRunnerInstanceReservations(tx, params, events)\n : 0;\n\n return {accepted: events.length, reservationsReleased, terminateIntentsHonored};\n });\n}\n\nexport async function listActiveRunnerInstanceCountsByTemplateTx(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string},\n): Promise<ActiveRunnerInstanceTemplateCount[]> {\n const rows = await tx\n .select({\n templateKey: providerRunners.templateKey,\n state: providerRunners.state,\n count: sql<number>`count(*)::int`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.state, divergenceCountStates),\n isNotNull(providerRunners.templateKey),\n ),\n )\n .groupBy(providerRunners.templateKey, providerRunners.state);\n\n return rows.flatMap((row) =>\n row.templateKey && isDivergenceCountState(row.state)\n ? [{templateKey: row.templateKey, state: row.state, count: row.count}]\n : [],\n );\n}\n\nexport async function countStaleEnrolledRunnerInstances(params: {\n graceSeconds: number;\n}): Promise<number> {\n const [row] = await db()\n .select({count: sql<number>`count(*)::int`})\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.state, 'running'),\n isNull(providerRunners.workspaceId),\n isNull(providerRunners.runnerSessionId),\n lt(providerRunners.reportedAt, staleRunnerInstanceCutoff(params.graceSeconds)),\n exists(\n db()\n .select({id: runnerControlSessions.id})\n .from(runnerControlSessions)\n .where(\n and(\n eq(runnerControlSessions.runnerInstanceId, providerRunners.id),\n isNull(runnerControlSessions.closedAt),\n gt(runnerControlSessions.expiresAt, sql`now()`),\n ),\n ),\n ),\n ),\n );\n\n return row?.count ?? 0;\n}\n\nexport async function listActiveRunnerInstances(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<RunnerInstance[]> {\n const rows = await db()\n .select()\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n inArray(providerRunners.state, activeStates),\n sql`${providerRunners.updatedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(providerRunners.updatedAt), desc(providerRunners.id))\n .limit(params.limit ?? 1000);\n\n return rows.map(toRunnerInstance);\n}\n\nexport async function listProvisionerTerminateIntents(params: {\n workspaceId: string;\n provisionerId: string;\n limit: number;\n}): Promise<string[]> {\n return await db().transaction(async (tx) => {\n const rows = await listProvisionerTerminateIntentRowsTx(tx, params);\n return rows.map((row) => row.providerRunnerId);\n });\n}\n\nexport async function listProvisionerTerminateIntentRowsTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n limit: number;\n },\n): Promise<RunnerInstanceTerminateIntent[]> {\n const rows = await provisionerTerminateIntentsQuery(tx, params)\n .orderBy(asc(providerRunners.providerRunnerId))\n .limit(params.limit + 1);\n\n const truncated = rows.length > params.limit;\n const returnedRows = truncated ? rows.slice(0, params.limit) : rows;\n if (truncated) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n limit: params.limit,\n returnedCount: returnedRows.length,\n },\n 'provisioner terminate intents truncated by poll-demand limit',\n );\n }\n\n return returnedRows.flatMap((row) =>\n row.providerRunnerId ? [{...row, providerRunnerId: row.providerRunnerId}] : [],\n );\n}\n\nfunction provisionerTerminateIntentsQuery(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string; providerRunnerIds?: string[]},\n) {\n const newerRunningJobExecutions = alias(runningJobExecutions, 'newer_running_jobs');\n\n return tx\n .select({\n providerRunnerId: providerRunners.providerRunnerId,\n reason: sql<RunnerInstanceTerminateIntentReason>`'job-cancelled'`,\n })\n .from(runningJobExecutions)\n .innerJoin(\n providerRunners,\n and(\n eq(providerRunners.workspaceId, runningJobExecutions.workspaceId),\n eq(providerRunners.provisionerId, runningJobExecutions.provisionerId),\n eq(providerRunners.providerRunnerId, runningJobExecutions.providerRunnerId),\n ),\n )\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n isNotNull(providerRunners.providerRunnerId),\n isNotNull(runningJobExecutions.cancellationRequestedAt),\n inArray(providerRunners.state, activeStates),\n params.providerRunnerIds && params.providerRunnerIds.length > 0\n ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds)\n : undefined,\n notExists(\n tx\n .select({id: newerRunningJobExecutions.id})\n .from(newerRunningJobExecutions)\n .where(\n and(\n eq(newerRunningJobExecutions.workspaceId, runningJobExecutions.workspaceId),\n eq(newerRunningJobExecutions.provisionerId, runningJobExecutions.provisionerId),\n eq(\n newerRunningJobExecutions.providerRunnerId,\n runningJobExecutions.providerRunnerId,\n ),\n or(\n gt(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt),\n and(\n eq(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt),\n gt(\n newerRunningJobExecutions.jobExecutionId,\n runningJobExecutions.jobExecutionId,\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n )\n .groupBy(providerRunners.providerRunnerId);\n}\n\nasync function listTerminateIntentsHonoredByTerminatedReportsTx(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportEvent[],\n): Promise<RunnerInstanceTerminateIntent[]> {\n if (!params.workspaceId) return [];\n const terminatedRunnerInstanceIds = [\n ...new Set(\n events.filter((event) => event.state === 'terminated').map((event) => event.providerRunnerId),\n ),\n ];\n if (terminatedRunnerInstanceIds.length === 0) return [];\n\n const rows = await provisionerTerminateIntentsQuery(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: terminatedRunnerInstanceIds,\n }).orderBy(asc(providerRunners.providerRunnerId));\n return rows.flatMap((row) =>\n row.providerRunnerId ? [{...row, providerRunnerId: row.providerRunnerId}] : [],\n );\n}\n\nexport async function reconcileRunnerInstances(\n params: ReconcileRunnerInstancesParams,\n): Promise<ReconcileRunnerInstancesDbResult> {\n const observedRunnerInstanceIds = [...new Set(params.observedRunnerInstanceIds)];\n\n return await db().transaction(async (tx) => {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`,\n );\n\n let absentIds: string[] = [];\n let reservationsReleased = 0;\n if (observedRunnerInstanceIds.length > 0) {\n const staleAbsentRows = await tx\n .select({\n id: providerRunners.id,\n providerRunnerId: providerRunners.providerRunnerId,\n })\n .from(providerRunners)\n .where(\n and(\n params.workspaceId\n ? eq(providerRunners.workspaceId, params.workspaceId)\n : isNull(providerRunners.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.state, activeStates),\n lt(\n providerRunners.reportedAt,\n sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`,\n ),\n notInArray(providerRunners.providerRunnerId, observedRunnerInstanceIds),\n ),\n );\n\n if (staleAbsentRows.length > 0) {\n const updated = await tx\n .update(providerRunners)\n .set({\n state: 'terminated',\n terminatedAt: sql`coalesce(${providerRunners.terminatedAt}, now())`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n staleAbsentRows.map((row) => row.id),\n ),\n inArray(providerRunners.state, activeStates),\n lt(\n providerRunners.reportedAt,\n sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`,\n ),\n ),\n )\n .returning({providerRunnerId: providerRunners.providerRunnerId});\n\n absentIds = updated.flatMap((row) => (row.providerRunnerId ? [row.providerRunnerId] : []));\n if (params.workspaceId) {\n reservationsReleased = await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: absentIds,\n });\n }\n }\n }\n\n const observedRows =\n observedRunnerInstanceIds.length === 0\n ? []\n : (\n await tx\n .select()\n .from(providerRunners)\n .where(\n and(\n params.workspaceId\n ? eq(providerRunners.workspaceId, params.workspaceId)\n : isNull(providerRunners.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, observedRunnerInstanceIds),\n ),\n )\n ).map(toRunnerInstance);\n\n const boundJobExecutions = params.workspaceId\n ? await listRunningJobExecutionsByRunnerInstanceTx(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: observedRunnerInstanceIds,\n })\n : [];\n\n return {\n observedRows,\n boundJobExecutionsByRunnerInstanceId: new Map(\n boundJobExecutions.map((jobExecution) => [jobExecution.providerRunnerId, jobExecution]),\n ),\n absentIds,\n reservationsReleased,\n };\n });\n}\n\nexport async function reapStaleRunnerInstances(params: {\n thresholdSeconds: number;\n limit: number;\n}): Promise<ReapStaleRunnerInstancesResult> {\n const cutoff = staleRunnerInstanceCutoff(params.thresholdSeconds);\n\n return await db().transaction(async (tx) => {\n const candidateRows = await tx\n .select({\n id: providerRunners.id,\n workspaceId: providerRunners.workspaceId,\n provisionerId: providerRunners.provisionerId,\n providerRunnerId: providerRunners.providerRunnerId,\n })\n .from(providerRunners)\n .where(staleRunnerInstanceWhere(tx, cutoff))\n .orderBy(asc(providerRunners.updatedAt), asc(providerRunners.id))\n .limit(params.limit);\n\n if (candidateRows.length === 0) return {reaped: 0, reservationsReleased: 0};\n\n const workspaceIds = [\n ...new Set(candidateRows.flatMap((row) => (row.workspaceId ? [row.workspaceId] : []))),\n ].sort();\n for (const workspaceId of workspaceIds) {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${workspaceId}))`);\n }\n\n const updatedRows = await tx\n .update(providerRunners)\n .set({\n state: 'failed',\n reason: 'stale-provisioner',\n failedAt: sql`coalesce(${providerRunners.failedAt}, now())`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n candidateRows.map((row) => row.id),\n ),\n staleRunnerInstanceWhere(tx, cutoff),\n ),\n )\n .returning({\n workspaceId: providerRunners.workspaceId,\n provisionerId: providerRunners.provisionerId,\n providerRunnerId: providerRunners.providerRunnerId,\n });\n\n let reservationsReleased = 0;\n for (const group of groupRunnerInstanceIds(updatedRows)) {\n reservationsReleased += await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: group.workspaceId,\n provisionerId: group.provisionerId,\n providerRunnerIds: group.providerRunnerIds,\n requireUnlinkedSession: false,\n });\n }\n\n return {reaped: updatedRows.length, reservationsReleased};\n });\n}\n\nasync function releaseTerminalRunnerInstanceReservations(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportEvent[],\n): Promise<number> {\n const terminalEvents = events.filter((event) => isTerminalState(event.state));\n if (terminalEvents.length === 0) return 0;\n\n return await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: terminalEvents.map((event) => event.providerRunnerId),\n });\n}\n\nasync function releaseTerminalRunnerInstanceReservationsByIds(\n tx: Tx,\n params: {\n workspaceId: string | null;\n provisionerId: string;\n providerRunnerIds: string[];\n requireUnlinkedSession?: boolean;\n },\n): Promise<number> {\n if (params.providerRunnerIds.length === 0) return 0;\n\n const reservationWorkspacePredicate =\n params.workspaceId === null\n ? sql``\n : sql`and ${eq(reservations.workspaceId, params.workspaceId)}`;\n\n const rows = await tx\n .select({\n id: providerRunners.id,\n releaseReservationId: sql<string | null>`coalesce(\n (select ${reservations.id}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.intendedReservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate}),\n (select ${reservations.id}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.reservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate})\n )`,\n releaseReservationWorkspaceId: sql<string | null>`coalesce(\n (select ${reservations.workspaceId}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.intendedReservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate}),\n (select ${reservations.workspaceId}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.reservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate})\n )`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, params.providerRunnerIds),\n inArray(providerRunners.state, terminalStates),\n or(\n isNotNull(providerRunners.reservationId),\n isNotNull(providerRunners.intendedReservationId),\n ),\n params.workspaceId === null\n ? undefined\n : or(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n or(\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.reservationId),\n ),\n ),\n ),\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n ),\n ),\n ),\n ),\n and(\n isNull(providerRunners.workspaceId),\n isNotNull(providerRunners.intendedReservationId),\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n ),\n ),\n ),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .for('update');\n\n if (rows.length === 0) return 0;\n\n const updated = await tx\n .update(providerRunners)\n .set({\n intendedReservationId: null,\n reservationReleasedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n rows.map((row) => row.id),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .returning({id: providerRunners.id});\n\n const releasesByReservationId = new Map<\n string,\n {workspaceId: string; reservationId: string; count: number}\n >();\n const updatedIds = new Set(updated.map((row) => row.id));\n for (const row of rows) {\n if (!updatedIds.has(row.id)) continue;\n if (!row.releaseReservationId || !row.releaseReservationWorkspaceId) continue;\n const key = `${row.releaseReservationWorkspaceId}:${row.releaseReservationId}`;\n const release = releasesByReservationId.get(key) ?? {\n workspaceId: row.releaseReservationWorkspaceId,\n reservationId: row.releaseReservationId,\n count: 0,\n };\n release.count += 1;\n releasesByReservationId.set(key, release);\n }\n\n if (releasesByReservationId.size === 0) return 0;\n\n let released = 0;\n for (const release of releasesByReservationId.values()) {\n released += await releaseReservationUnits(tx, {\n workspaceId: release.workspaceId,\n provisionerId: params.provisionerId,\n releases: [{reservationId: release.reservationId, count: release.count}],\n });\n }\n return released;\n}\n\nfunction staleRunnerInstanceCutoff(thresholdSeconds: number): SQL {\n return sql`now() - (${thresholdSeconds} || ' seconds')::interval`;\n}\n\nfunction staleRunnerInstanceWhere(tx: Tx, cutoff: SQL): SQL<boolean> {\n return and(\n inArray(providerRunners.state, activeStates),\n lt(providerRunners.reportedAt, cutoff),\n lt(providerRunners.updatedAt, cutoff),\n exists(\n tx\n .select({id: provisionerTokens.id})\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, providerRunners.provisionerId),\n or(isNull(provisionerTokens.lastSeenAt), lt(provisionerTokens.lastSeenAt, cutoff)),\n ),\n ),\n ),\n notExists(\n tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, providerRunners.workspaceId),\n eq(runningJobExecutions.provisionerId, providerRunners.provisionerId),\n eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId),\n ),\n ),\n ),\n notExists(\n tx\n .select({id: runnerSessions.id})\n .from(runnerSessions)\n .where(\n and(\n eq(runnerSessions.workspaceId, providerRunners.workspaceId),\n eq(runnerSessions.provisionerId, providerRunners.provisionerId),\n eq(runnerSessions.providerRunnerId, providerRunners.providerRunnerId),\n sql`${runnerSessions.updatedAt} >= ${cutoff}`,\n ),\n ),\n ),\n ) as SQL<boolean>;\n}\n\nfunction groupRunnerInstanceIds(\n rows: Array<{\n workspaceId: string | null;\n provisionerId: string;\n providerRunnerId: string | null;\n }>,\n): Array<{workspaceId: string | null; provisionerId: string; providerRunnerIds: string[]}> {\n const groups = new Map<\n string,\n {workspaceId: string | null; provisionerId: string; providerRunnerIds: string[]}\n >();\n for (const row of rows) {\n if (!row.providerRunnerId) continue;\n const key = `${row.workspaceId ?? ''}:${row.provisionerId}`;\n const group = groups.get(key) ?? {\n workspaceId: row.workspaceId,\n provisionerId: row.provisionerId,\n providerRunnerIds: [],\n };\n group.providerRunnerIds.push(row.providerRunnerId);\n groups.set(key, group);\n }\n return [...groups.values()];\n}\n\nasync function hydrateRunnerSessionIdsFromConsumedTokens(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportRow[],\n): Promise<RunnerInstanceReportRow[]> {\n if (!params.workspaceId) return events;\n const providerRunnerIds = [...new Set(events.map((event) => event.providerRunnerId))];\n if (providerRunnerIds.length === 0) return events;\n\n const tokenRows = await tx\n .select({\n providerRunnerId: ephemeralRegistrationTokens.providerRunnerId,\n consumedSessionId: ephemeralRegistrationTokens.consumedSessionId,\n })\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n inArray(ephemeralRegistrationTokens.providerRunnerId, providerRunnerIds),\n isNotNull(ephemeralRegistrationTokens.consumedSessionId),\n ),\n )\n .orderBy(\n desc(ephemeralRegistrationTokens.consumedAt),\n desc(ephemeralRegistrationTokens.createdAt),\n );\n\n const consumedSessionIdsByRunnerInstanceId = new Map<string, string>();\n for (const row of tokenRows) {\n if (!row.consumedSessionId) continue;\n if (consumedSessionIdsByRunnerInstanceId.has(row.providerRunnerId)) continue;\n consumedSessionIdsByRunnerInstanceId.set(row.providerRunnerId, row.consumedSessionId);\n }\n\n if (consumedSessionIdsByRunnerInstanceId.size === 0) return events;\n\n return events.map((event) => {\n const consumedSessionId = consumedSessionIdsByRunnerInstanceId.get(event.providerRunnerId);\n if (!consumedSessionId || event.runnerSessionId === consumedSessionId) return event;\n return {...event, runnerSessionId: consumedSessionId};\n });\n}\n\nfunction aggregateEvents(\n events: RunnerInstanceReportEvent[],\n receivedAt: Date,\n): RunnerInstanceReportRow[] {\n const byRunnerInstanceId = new Map<string, RunnerInstanceReportRow>();\n for (const rawEvent of events) {\n const event = toRunnerInstanceReportRow(rawEvent, receivedAt);\n const existing = byRunnerInstanceId.get(event.providerRunnerId);\n if (existing) mergeMilestones(existing, event);\n if (!existing || compareRunnerInstanceReportEvents(event, existing) > 0) {\n byRunnerInstanceId.set(\n event.providerRunnerId,\n existing ? mergeProjectionMetadata(event, existing) : event,\n );\n }\n }\n return [...byRunnerInstanceId.values()];\n}\n\nfunction toRunnerInstanceReportRow(\n event: RunnerInstanceReportEvent,\n receivedAt: Date,\n): RunnerInstanceReportRow {\n const reportedAt = event.reportedAt > receivedAt ? receivedAt : event.reportedAt;\n return {\n ...event,\n reportedAt,\n startedAt: event.state === 'running' ? reportedAt : null,\n stoppingAt: event.state === 'stopping' ? reportedAt : null,\n stoppedAt: event.state === 'stopped' ? reportedAt : null,\n failedAt: event.state === 'failed' ? reportedAt : null,\n terminatedAt: event.state === 'terminated' ? reportedAt : null,\n };\n}\n\nfunction mergeMilestones(target: RunnerInstanceReportRow, source: RunnerInstanceReportRow) {\n target.startedAt = earliestDate(target.startedAt, source.startedAt);\n target.stoppingAt = earliestDate(target.stoppingAt, source.stoppingAt);\n target.stoppedAt = earliestDate(target.stoppedAt, source.stoppedAt);\n target.failedAt = earliestDate(target.failedAt, source.failedAt);\n target.terminatedAt = earliestDate(target.terminatedAt, source.terminatedAt);\n}\n\nfunction mergeProjectionMetadata(\n event: RunnerInstanceReportRow,\n existing: RunnerInstanceReportRow,\n): RunnerInstanceReportRow {\n return {\n ...event,\n reservationId: event.reservationId ?? existing.reservationId,\n templateKey: event.templateKey ?? existing.templateKey,\n runnerSessionId: event.runnerSessionId ?? existing.runnerSessionId,\n providerKind: event.providerKind ?? existing.providerKind,\n ...pickMilestones(existing),\n };\n}\n\nfunction pickMilestones(event: RunnerInstanceReportRow) {\n return {\n startedAt: event.startedAt,\n stoppingAt: event.stoppingAt,\n stoppedAt: event.stoppedAt,\n failedAt: event.failedAt,\n terminatedAt: event.terminatedAt,\n };\n}\n\nfunction earliestDate(a: Date | null, b: Date | null): Date | null {\n if (!a) return b;\n if (!b) return a;\n return a < b ? a : b;\n}\n\nfunction compareRunnerInstanceReportEvents(\n a: RunnerInstanceReportEvent,\n b: RunnerInstanceReportEvent,\n): number {\n const timeDelta = a.reportedAt.getTime() - b.reportedAt.getTime();\n const rankDelta = getRunnerInstanceStateRank(a.state) - getRunnerInstanceStateRank(b.state);\n if (rankDelta !== 0) return rankDelta;\n return timeDelta;\n}\n\nfunction getRunnerInstanceStateRank(state: RunnerInstanceState): number {\n switch (state) {\n case 'starting':\n return 1;\n case 'running':\n return 2;\n case 'stopping':\n return 3;\n case 'stopped':\n return 4;\n case 'failed':\n return 5;\n case 'terminated':\n return 6;\n }\n}\n\nfunction providerRunnerStateRank(state: SQL | typeof providerRunners.state): SQL<number> {\n return sql<number>`\n CASE ${state}\n WHEN 'starting' THEN 1\n WHEN 'running' THEN 2\n WHEN 'stopping' THEN 3\n WHEN 'stopped' THEN 4\n WHEN 'failed' THEN 5\n WHEN 'terminated' THEN 6\n ELSE 0\n END\n `;\n}\n\nfunction providerRunnerProjectionUpdateCondition(): SQL<boolean> {\n return sql<boolean>`\n ${providerRunnerStateRank(sql`excluded.state`)} > ${providerRunnerStateRank(providerRunners.state)}\n OR (\n ${providerRunnerStateRank(sql`excluded.state`)} = ${providerRunnerStateRank(providerRunners.state)}\n AND excluded.reported_at >= ${providerRunners.reportedAt}\n )\n `;\n}\n\nfunction providerRunnerMilestoneUpdateCondition(): SQL<boolean> {\n return sql<boolean>`\n ${milestoneNeedsUpdate(providerRunners.startedAt, sql`excluded.started_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.stoppingAt, sql`excluded.stopping_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.stoppedAt, sql`excluded.stopped_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.failedAt, sql`excluded.failed_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.terminatedAt, sql`excluded.terminated_at`)}\n `;\n}\n\nfunction milestoneNeedsUpdate(\n current: SQL | RunnerInstanceMilestoneColumn,\n incoming: SQL,\n): SQL<boolean> {\n return sql<boolean>`${incoming} IS NOT NULL AND (${current} IS NULL OR ${incoming} < ${current})`;\n}\n\nfunction firstObservedAt(current: SQL | RunnerInstanceMilestoneColumn, incoming: SQL) {\n return sql`\n CASE\n WHEN ${incoming} IS NULL THEN ${current}\n WHEN ${current} IS NULL THEN ${incoming}\n ELSE least(${current}, ${incoming})\n END\n `;\n}\n\nexport function isTerminalState(state: RunnerInstanceState): boolean {\n return terminalStates.includes(state as (typeof terminalStates)[number]);\n}\n\nfunction isDivergenceCountState(\n state: RunnerInstanceState,\n): state is (typeof divergenceCountStates)[number] {\n return divergenceCountStates.includes(state as (typeof divergenceCountStates)[number]);\n}\n"],"names":["logger","and","asc","desc","eq","exists","gt","inArray","isNotNull","isNull","lt","notExists","notInArray","or","sql","alias","sanitizeRunnerLabels","db","listRunningJobExecutionsByRunnerInstanceTx","releaseReservationUnits","ephemeralRegistrationTokens","provisionerTokens","reservations","runnerControlSessions","providerRunners","toRunnerInstance","runnerSessions","runningJobExecutions","terminalStates","activeStates","divergenceCountStates","attachRunnerInstanceProviderId","params","updated","update","set","providerRunnerId","updatedAt","where","id","runnerInstanceId","provisionerId","state","returning","length","reportRunnerInstances","events","accepted","reservationsReleased","terminateIntentsHonored","transaction","tx","receivedAt","Date","aggregatedEvents","aggregateEvents","hasTerminalEvent","some","event","isTerminalState","execute","workspaceId","hydrateRunnerSessionIdsFromConsumedTokens","listTerminateIntentsHonoredByTerminatedReportsTx","values","map","reservationId","templateKey","labels","scope","logLevel","source","reason","runnerSessionId","providerKind","reportedAt","startedAt","stoppingAt","stoppedAt","failedAt","terminatedAt","insert","onConflictDoUpdate","target","targetWhere","providerRunnerProjectionUpdateCondition","firstObservedAt","setWhere","providerRunnerMilestoneUpdateCondition","releaseTerminalRunnerInstanceReservations","listActiveRunnerInstanceCountsByTemplateTx","rows","select","count","from","groupBy","flatMap","row","isDivergenceCountState","countStaleEnrolledRunnerInstances","staleRunnerInstanceCutoff","graceSeconds","closedAt","expiresAt","listActiveRunnerInstances","windowSeconds","orderBy","limit","listProvisionerTerminateIntents","listProvisionerTerminateIntentRowsTx","provisionerTerminateIntentsQuery","truncated","returnedRows","slice","warn","returnedCount","newerRunningJobExecutions","innerJoin","cancellationRequestedAt","providerRunnerIds","undefined","jobExecutionId","terminatedRunnerInstanceIds","Set","filter","reconcileRunnerInstances","observedRunnerInstanceIds","absentIds","staleAbsentRows","terminateGraceSeconds","releaseTerminalRunnerInstanceReservationsByIds","observedRows","boundJobExecutions","boundJobExecutionsByRunnerInstanceId","Map","jobExecution","reapStaleRunnerInstances","cutoff","thresholdSeconds","candidateRows","staleRunnerInstanceWhere","reaped","workspaceIds","sort","updatedRows","group","groupRunnerInstanceIds","requireUnlinkedSession","terminalEvents","reservationWorkspacePredicate","releaseReservationId","intendedReservationId","releaseReservationWorkspaceId","reservationReleasedAt","for","releasesByReservationId","updatedIds","has","key","release","get","size","released","releases","lastSeenAt","groups","push","tokenRows","consumedSessionId","consumedAt","createdAt","consumedSessionIdsByRunnerInstanceId","byRunnerInstanceId","rawEvent","toRunnerInstanceReportRow","existing","mergeMilestones","compareRunnerInstanceReportEvents","mergeProjectionMetadata","earliestDate","pickMilestones","a","b","timeDelta","getTime","rankDelta","getRunnerInstanceStateRank","providerRunnerStateRank","milestoneNeedsUpdate","current","incoming","includes"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/db/runner-instances.ts"],"sourcesContent":["import {logger} from '@shipfox/node-opentelemetry';\nimport {\n and,\n asc,\n desc,\n eq,\n exists,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n notExists,\n notInArray,\n or,\n type SQL,\n sql,\n} from 'drizzle-orm';\nimport {alias} from 'drizzle-orm/pg-core';\nimport {config} from '#config.js';\nimport type {RunnerInstance, RunnerInstanceState} from '#core/entities/runner-instance.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {recordRunnerReservationCapacityFailure} from '#metrics/index.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {\n listRunningJobExecutionsByRunnerInstanceTx,\n type RunnerInstanceBoundJobExecution,\n} from './job-executions.js';\nimport {lockRunnerReservationAdvisoryKeysTx} from './reservation-locks.js';\nimport {releaseReservationUnits} from './reservations.js';\nimport {validateRunnerReservationCapacityTx} from './runner-assignments.js';\nimport {terminalStates} from './runner-states.js';\nimport {ephemeralRegistrationTokens} from './schema/ephemeral-registration-tokens.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {reservations} from './schema/reservations.js';\nimport {runnerControlSessions} from './schema/runner-control-sessions.js';\nimport {providerRunners, toRunnerInstance} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport const activeStates = [\n 'starting',\n 'running',\n 'stopping',\n] as const satisfies readonly RunnerInstanceState[];\nexport const divergenceCountStates = ['starting', 'running'] as const satisfies readonly Extract<\n RunnerInstanceState,\n 'starting' | 'running'\n>[];\n\nexport type RunnerInstanceTerminateIntentReason = 'activation-timeout' | 'job-cancelled';\n\nexport interface RunnerInstanceTerminateIntent {\n providerRunnerId: string;\n reason: RunnerInstanceTerminateIntentReason;\n activationTimeoutRetry?: boolean;\n}\n\nexport interface ActiveRunnerInstanceTemplateCount {\n templateKey: string;\n state: (typeof divergenceCountStates)[number];\n count: number;\n}\n\nexport interface RunnerInstanceReportEvent {\n providerRunnerId: string;\n reservationId: string | null;\n templateKey: string | null;\n labels: string[];\n state: RunnerInstanceState;\n reason: string | null;\n runnerSessionId: string | null;\n providerKind: string | null;\n reportedAt: Date;\n}\n\nexport interface ReportRunnerInstancesParams {\n scope: 'installation' | 'workspace';\n workspaceId: string | null;\n provisionerId: string;\n events: RunnerInstanceReportEvent[];\n}\n\nexport interface ReconcileRunnerInstancesParams {\n workspaceId: string | null;\n provisionerId: string;\n observedRunnerInstanceIds: string[];\n terminateGraceSeconds: number;\n}\n\nexport interface ReconcileRunnerInstancesDbResult {\n observedRows: RunnerInstance[];\n boundJobExecutionsByRunnerInstanceId: Map<string, RunnerInstanceBoundJobExecution>;\n absentIds: string[];\n reservationsReleased: number;\n}\n\nexport interface ReapStaleRunnerInstancesResult {\n reaped: number;\n reservationsReleased: number;\n}\n\nexport async function attachRunnerInstanceProviderId(params: {\n runnerInstanceId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n const updated = await db()\n .update(providerRunners)\n .set({providerRunnerId: params.providerRunnerId, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.providerRunnerId),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({id: providerRunners.id});\n return updated.length === 1;\n}\n\ninterface RunnerInstanceReportRow extends RunnerInstanceReportEvent {\n startedAt: Date | null;\n stoppingAt: Date | null;\n stoppedAt: Date | null;\n failedAt: Date | null;\n terminatedAt: Date | null;\n}\n\ntype RunnerInstanceMilestoneColumn =\n | typeof providerRunners.startedAt\n | typeof providerRunners.stoppingAt\n | typeof providerRunners.stoppedAt\n | typeof providerRunners.failedAt\n | typeof providerRunners.terminatedAt;\n\nexport async function reportRunnerInstances(params: ReportRunnerInstancesParams): Promise<{\n accepted: number;\n reservationsReleased: number;\n terminateIntentsHonored: RunnerInstanceTerminateIntent[];\n}> {\n if (params.events.length === 0)\n return {accepted: 0, reservationsReleased: 0, terminateIntentsHonored: []};\n\n return await db().transaction(async (tx) => {\n const receivedAt = new Date();\n const aggregatedEvents = aggregateEvents(params.events, receivedAt);\n const hasTerminalEvent = aggregatedEvents.some((event) => isTerminalState(event.state));\n\n if (hasTerminalEvent) {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`,\n );\n }\n\n const events = await hydrateRunnerSessionIdsFromConsumedTokens(tx, params, aggregatedEvents);\n const reservationSafeEvents = await guardReportedReservationIdsTx(tx, params, events);\n const terminateIntentsHonored = await listTerminateIntentsHonoredByTerminatedReportsTx(\n tx,\n params,\n reservationSafeEvents,\n );\n\n const values = reservationSafeEvents.map((event) => ({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerId: event.providerRunnerId,\n reservationId: event.reservationId,\n templateKey: event.templateKey,\n labels: sanitizeRunnerLabels(event.labels, {\n scope: params.scope,\n logLevel: 'debug',\n source: 'runner instance report',\n }),\n state: event.state,\n reason: event.reason,\n runnerSessionId: event.runnerSessionId,\n providerKind: event.providerKind,\n reportedAt: event.reportedAt > receivedAt ? receivedAt : event.reportedAt,\n startedAt: event.startedAt,\n stoppingAt: event.stoppingAt,\n stoppedAt: event.stoppedAt,\n failedAt: event.failedAt,\n terminatedAt: event.terminatedAt,\n }));\n\n await tx\n .insert(providerRunners)\n .values(values)\n .onConflictDoUpdate({\n target: [providerRunners.provisionerId, providerRunners.providerRunnerId],\n targetWhere: isNotNull(providerRunners.providerRunnerId),\n set: {\n reservationId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(${providerRunners.reservationId}, excluded.reservation_id) ELSE ${providerRunners.reservationId} END`,\n templateKey: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.template_key, ${providerRunners.templateKey}) ELSE ${providerRunners.templateKey} END`,\n labels: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.labels ELSE ${providerRunners.labels} END`,\n state: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.state ELSE ${providerRunners.state} END`,\n reason: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reason ELSE ${providerRunners.reason} END`,\n runnerSessionId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(${providerRunners.runnerSessionId}, excluded.runner_session_id) ELSE ${providerRunners.runnerSessionId} END`,\n providerKind: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.provider_kind, ${providerRunners.providerKind}) ELSE ${providerRunners.providerKind} END`,\n reportedAt: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reported_at ELSE ${providerRunners.reportedAt} END`,\n startedAt: firstObservedAt(providerRunners.startedAt, sql`excluded.started_at`),\n stoppingAt: firstObservedAt(providerRunners.stoppingAt, sql`excluded.stopping_at`),\n stoppedAt: firstObservedAt(providerRunners.stoppedAt, sql`excluded.stopped_at`),\n failedAt: firstObservedAt(providerRunners.failedAt, sql`excluded.failed_at`),\n terminatedAt: firstObservedAt(providerRunners.terminatedAt, sql`excluded.terminated_at`),\n updatedAt: sql`now()`,\n },\n setWhere: sql`\n ${providerRunnerProjectionUpdateCondition()}\n OR ${providerRunnerMilestoneUpdateCondition()}\n `,\n });\n\n const reservationsReleased = hasTerminalEvent\n ? await releaseTerminalRunnerInstanceReservations(tx, params, reservationSafeEvents)\n : 0;\n\n return {\n accepted: reservationSafeEvents.length,\n reservationsReleased,\n terminateIntentsHonored,\n };\n });\n}\n\nasync function guardReportedReservationIdsTx(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportRow[],\n): Promise<RunnerInstanceReportRow[]> {\n const reservationIds = [\n ...new Set(events.flatMap((event) => (event.reservationId ? [event.reservationId] : []))),\n ].sort();\n if (reservationIds.length === 0) return events;\n\n await lockRunnerReservationAdvisoryKeysTx(tx, {\n provisionerId: params.provisionerId,\n reservationIds,\n });\n const providerRunnerIds = events.map((event) => event.providerRunnerId);\n const existingRows = await tx\n .select({\n providerRunnerId: providerRunners.providerRunnerId,\n reservationId: providerRunners.reservationId,\n intendedReservationId: providerRunners.intendedReservationId,\n reservationReleasedAt: providerRunners.reservationReleasedAt,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, providerRunnerIds),\n ),\n )\n .for('update');\n const existingByProviderRunnerId = new Map(\n existingRows.flatMap((row) =>\n row.providerRunnerId ? [[row.providerRunnerId, row] as const] : [],\n ),\n );\n const candidateReservationByProviderRunnerId = new Map<string, string>();\n for (const event of events) {\n if (!event.reservationId) continue;\n if (isTerminalState(event.state)) continue;\n const existing = existingByProviderRunnerId.get(event.providerRunnerId);\n if (existing?.reservationId || existing?.intendedReservationId === event.reservationId)\n continue;\n if (existing?.intendedReservationId || existing?.reservationReleasedAt) continue;\n candidateReservationByProviderRunnerId.set(event.providerRunnerId, event.reservationId);\n }\n\n const validation = await validateRunnerReservationCapacityTx(\n tx,\n {\n provisionerId: params.provisionerId,\n requests: [...candidateReservationByProviderRunnerId.values()].map((reservationId) => ({\n reservationId,\n count: 1,\n })),\n },\n {advisoryLocksHeld: true},\n );\n for (const {reason, count} of validation.unavailableByReservation.values())\n recordRunnerReservationCapacityFailure(reason, count);\n\n const remainingAcceptedByReservation = new Map(validation.acceptedByReservation);\n return events.map((event) => {\n const existing = existingByProviderRunnerId.get(event.providerRunnerId);\n const reservationId = candidateReservationByProviderRunnerId.get(event.providerRunnerId);\n if (!reservationId) {\n if (event.reservationId && isTerminalState(event.state)) {\n // Terminal cleanup releases the IDs stored on the projection row. An arbitrary\n // terminal report must not consume reservation capacity during that cleanup.\n const matchesExistingReservation =\n existing !== undefined &&\n (existing.reservationId === event.reservationId ||\n existing.intendedReservationId === event.reservationId);\n if (!matchesExistingReservation) return {...event, reservationId: null};\n }\n if (\n event.reservationId &&\n existing?.intendedReservationId &&\n existing.intendedReservationId !== event.reservationId\n )\n return {...event, reservationId: null};\n if (event.reservationId && existing?.reservationReleasedAt)\n return {...event, reservationId: null};\n return event;\n }\n const remaining = remainingAcceptedByReservation.get(reservationId) ?? 0;\n if (remaining === 0) return {...event, reservationId: null};\n remainingAcceptedByReservation.set(reservationId, remaining - 1);\n return event;\n });\n}\n\nexport async function listActiveRunnerInstanceCountsByTemplateTx(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string},\n): Promise<ActiveRunnerInstanceTemplateCount[]> {\n const rows = await tx\n .select({\n templateKey: providerRunners.templateKey,\n state: providerRunners.state,\n count: sql<number>`count(*)::int`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.state, divergenceCountStates),\n isNotNull(providerRunners.templateKey),\n ),\n )\n .groupBy(providerRunners.templateKey, providerRunners.state);\n\n return rows.flatMap((row) =>\n row.templateKey && isDivergenceCountState(row.state)\n ? [{templateKey: row.templateKey, state: row.state, count: row.count}]\n : [],\n );\n}\n\nexport async function countStaleEnrolledRunnerInstances(params: {\n graceSeconds: number;\n}): Promise<number> {\n const [row] = await db()\n .select({count: sql<number>`count(*)::int`})\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.state, 'running'),\n isNull(providerRunners.workspaceId),\n isNull(providerRunners.runnerSessionId),\n lt(providerRunners.reportedAt, staleRunnerInstanceCutoff(params.graceSeconds)),\n exists(\n db()\n .select({id: runnerControlSessions.id})\n .from(runnerControlSessions)\n .where(\n and(\n eq(runnerControlSessions.runnerInstanceId, providerRunners.id),\n isNull(runnerControlSessions.closedAt),\n gt(runnerControlSessions.expiresAt, sql`now()`),\n ),\n ),\n ),\n ),\n );\n\n return row?.count ?? 0;\n}\n\nexport async function listActiveRunnerInstances(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<RunnerInstance[]> {\n const rows = await db()\n .select()\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n inArray(providerRunners.state, activeStates),\n sql`${providerRunners.updatedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(providerRunners.updatedAt), desc(providerRunners.id))\n .limit(params.limit ?? 1000);\n\n return rows.map(toRunnerInstance);\n}\n\nexport async function listProvisionerTerminateIntents(params: {\n workspaceId: string;\n provisionerId: string;\n limit: number;\n}): Promise<string[]> {\n return await db().transaction(async (tx) => {\n const rows = await listProvisionerTerminateIntentRowsTx(tx, params);\n return rows.map((row) => row.providerRunnerId);\n });\n}\n\nexport async function listProvisionerTerminateIntentRowsTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n limit: number;\n },\n): Promise<RunnerInstanceTerminateIntent[]> {\n const rows = await provisionerTerminateIntentsQuery(tx, params)\n .orderBy(asc(providerRunners.providerRunnerId))\n .limit(params.limit + 1);\n\n const truncated = rows.length > params.limit;\n const returnedRows = truncated ? rows.slice(0, params.limit) : rows;\n if (truncated) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n limit: params.limit,\n returnedCount: returnedRows.length,\n },\n 'provisioner terminate intents truncated by poll-demand limit',\n );\n }\n\n const activationTimeoutRunnerIds = returnedRows.flatMap((row) =>\n row.reason === 'activation-timeout' && row.providerRunnerId ? [row.providerRunnerId] : [],\n );\n if (activationTimeoutRunnerIds.length > 0) {\n await tx\n .update(providerRunners)\n .set({reservationReleasedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, activationTimeoutRunnerIds),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n }\n\n return returnedRows.flatMap((row) => toRunnerInstanceTerminateIntent(row));\n}\n\nfunction toRunnerInstanceTerminateIntent(row: {\n providerRunnerId: string | null;\n reason: RunnerInstanceTerminateIntentReason;\n activationTimeoutRetry: boolean;\n}): RunnerInstanceTerminateIntent[] {\n if (!row.providerRunnerId) return [];\n\n return [\n {\n providerRunnerId: row.providerRunnerId,\n reason: row.reason,\n ...(row.reason === 'activation-timeout' && row.activationTimeoutRetry\n ? {activationTimeoutRetry: true}\n : {}),\n },\n ];\n}\n\nfunction provisionerTerminateIntentsQuery(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string; providerRunnerIds?: string[]},\n) {\n const newerRunningJobExecutions = alias(runningJobExecutions, 'newer_running_jobs');\n const latestCancelledJob = exists(\n tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId),\n isNotNull(runningJobExecutions.cancellationRequestedAt),\n notExists(\n tx\n .select({id: newerRunningJobExecutions.id})\n .from(newerRunningJobExecutions)\n .where(\n and(\n eq(newerRunningJobExecutions.workspaceId, runningJobExecutions.workspaceId),\n eq(newerRunningJobExecutions.provisionerId, runningJobExecutions.provisionerId),\n eq(\n newerRunningJobExecutions.providerRunnerId,\n runningJobExecutions.providerRunnerId,\n ),\n or(\n gt(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt),\n and(\n eq(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt),\n gt(\n newerRunningJobExecutions.jobExecutionId,\n runningJobExecutions.jobExecutionId,\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n );\n const activationTimeout = and(\n eq(providerRunners.launchKind, 'demand'),\n isNull(providerRunners.runnerSessionId),\n lt(\n providerRunners.createdAt,\n sql`now() - (${config.RUNNER_DEMAND_ACTIVATION_TIMEOUT_SECONDS} || ' seconds')::interval`,\n ),\n notExists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n or(\n eq(reservations.id, providerRunners.reservationId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n gt(reservations.expiresAt, sql`now()`),\n ),\n ),\n ),\n );\n\n return tx\n .select({\n providerRunnerId: providerRunners.providerRunnerId,\n activationTimeoutRetry: sql<boolean>`${providerRunners.reservationReleasedAt} is not null`,\n reason: sql<RunnerInstanceTerminateIntentReason>`case\n when ${activationTimeout} then 'activation-timeout'\n else 'job-cancelled'\n end`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n isNotNull(providerRunners.providerRunnerId),\n inArray(providerRunners.state, activeStates),\n params.providerRunnerIds && params.providerRunnerIds.length > 0\n ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds)\n : undefined,\n or(latestCancelledJob, activationTimeout),\n ),\n );\n}\n\nasync function listTerminateIntentsHonoredByTerminatedReportsTx(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportEvent[],\n): Promise<RunnerInstanceTerminateIntent[]> {\n if (!params.workspaceId) return [];\n const terminatedRunnerInstanceIds = [\n ...new Set(\n events.filter((event) => event.state === 'terminated').map((event) => event.providerRunnerId),\n ),\n ];\n if (terminatedRunnerInstanceIds.length === 0) return [];\n\n const rows = await provisionerTerminateIntentsQuery(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: terminatedRunnerInstanceIds,\n }).orderBy(asc(providerRunners.providerRunnerId));\n return rows.flatMap((row) => toRunnerInstanceTerminateIntent(row));\n}\n\nexport async function reconcileRunnerInstances(\n params: ReconcileRunnerInstancesParams,\n): Promise<ReconcileRunnerInstancesDbResult> {\n const observedRunnerInstanceIds = [...new Set(params.observedRunnerInstanceIds)];\n\n return await db().transaction(async (tx) => {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`,\n );\n\n let absentIds: string[] = [];\n let reservationsReleased = 0;\n if (observedRunnerInstanceIds.length > 0) {\n const staleAbsentRows = await tx\n .select({\n id: providerRunners.id,\n providerRunnerId: providerRunners.providerRunnerId,\n })\n .from(providerRunners)\n .where(\n and(\n params.workspaceId\n ? eq(providerRunners.workspaceId, params.workspaceId)\n : isNull(providerRunners.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.state, activeStates),\n lt(\n providerRunners.reportedAt,\n sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`,\n ),\n notInArray(providerRunners.providerRunnerId, observedRunnerInstanceIds),\n ),\n );\n\n if (staleAbsentRows.length > 0) {\n const updated = await tx\n .update(providerRunners)\n .set({\n state: 'terminated',\n terminatedAt: sql`coalesce(${providerRunners.terminatedAt}, now())`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n staleAbsentRows.map((row) => row.id),\n ),\n inArray(providerRunners.state, activeStates),\n lt(\n providerRunners.reportedAt,\n sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`,\n ),\n ),\n )\n .returning({providerRunnerId: providerRunners.providerRunnerId});\n\n absentIds = updated.flatMap((row) => (row.providerRunnerId ? [row.providerRunnerId] : []));\n if (params.workspaceId) {\n reservationsReleased = await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: absentIds,\n });\n }\n }\n }\n\n const observedRows =\n observedRunnerInstanceIds.length === 0\n ? []\n : (\n await tx\n .select()\n .from(providerRunners)\n .where(\n and(\n params.workspaceId\n ? eq(providerRunners.workspaceId, params.workspaceId)\n : isNull(providerRunners.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, observedRunnerInstanceIds),\n ),\n )\n ).map(toRunnerInstance);\n\n const boundJobExecutions = params.workspaceId\n ? await listRunningJobExecutionsByRunnerInstanceTx(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: observedRunnerInstanceIds,\n })\n : [];\n\n return {\n observedRows,\n boundJobExecutionsByRunnerInstanceId: new Map(\n boundJobExecutions.map((jobExecution) => [jobExecution.providerRunnerId, jobExecution]),\n ),\n absentIds,\n reservationsReleased,\n };\n });\n}\n\nexport async function reapStaleRunnerInstances(params: {\n thresholdSeconds: number;\n limit: number;\n}): Promise<ReapStaleRunnerInstancesResult> {\n const cutoff = staleRunnerInstanceCutoff(params.thresholdSeconds);\n\n return await db().transaction(async (tx) => {\n const candidateRows = await tx\n .select({\n id: providerRunners.id,\n workspaceId: providerRunners.workspaceId,\n provisionerId: providerRunners.provisionerId,\n providerRunnerId: providerRunners.providerRunnerId,\n })\n .from(providerRunners)\n .where(staleRunnerInstanceWhere(tx, cutoff))\n .orderBy(asc(providerRunners.updatedAt), asc(providerRunners.id))\n .limit(params.limit);\n\n if (candidateRows.length === 0) return {reaped: 0, reservationsReleased: 0};\n\n const workspaceIds = [\n ...new Set(candidateRows.flatMap((row) => (row.workspaceId ? [row.workspaceId] : []))),\n ].sort();\n for (const workspaceId of workspaceIds) {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${workspaceId}))`);\n }\n\n const updatedRows = await tx\n .update(providerRunners)\n .set({\n state: 'failed',\n reason: 'stale-provisioner',\n failedAt: sql`coalesce(${providerRunners.failedAt}, now())`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n candidateRows.map((row) => row.id),\n ),\n staleRunnerInstanceWhere(tx, cutoff),\n ),\n )\n .returning({\n workspaceId: providerRunners.workspaceId,\n provisionerId: providerRunners.provisionerId,\n providerRunnerId: providerRunners.providerRunnerId,\n });\n\n let reservationsReleased = 0;\n for (const group of groupRunnerInstanceIds(updatedRows)) {\n reservationsReleased += await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: group.workspaceId,\n provisionerId: group.provisionerId,\n providerRunnerIds: group.providerRunnerIds,\n requireUnlinkedSession: false,\n });\n }\n\n return {reaped: updatedRows.length, reservationsReleased};\n });\n}\n\nasync function releaseTerminalRunnerInstanceReservations(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportEvent[],\n): Promise<number> {\n const terminalEvents = events.filter((event) => isTerminalState(event.state));\n if (terminalEvents.length === 0) return 0;\n\n return await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: terminalEvents.map((event) => event.providerRunnerId),\n });\n}\n\nasync function releaseTerminalRunnerInstanceReservationsByIds(\n tx: Tx,\n params: {\n workspaceId: string | null;\n provisionerId: string;\n providerRunnerIds: string[];\n requireUnlinkedSession?: boolean;\n },\n): Promise<number> {\n if (params.providerRunnerIds.length === 0) return 0;\n\n const reservationWorkspacePredicate =\n params.workspaceId === null\n ? sql``\n : sql`and ${eq(reservations.workspaceId, params.workspaceId)}`;\n\n const rows = await tx\n .select({\n id: providerRunners.id,\n releaseReservationId: sql<string | null>`coalesce(\n (select ${reservations.id}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.intendedReservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate}),\n (select ${reservations.id}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.reservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate})\n )`,\n releaseReservationWorkspaceId: sql<string | null>`coalesce(\n (select ${reservations.workspaceId}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.intendedReservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate}),\n (select ${reservations.workspaceId}\n from ${reservations}\n where ${reservations.id} = ${providerRunners.reservationId}\n and ${reservations.provisionerId} = ${params.provisionerId}\n ${reservationWorkspacePredicate})\n )`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, params.providerRunnerIds),\n inArray(providerRunners.state, terminalStates),\n or(\n isNotNull(providerRunners.reservationId),\n isNotNull(providerRunners.intendedReservationId),\n ),\n params.workspaceId === null\n ? undefined\n : or(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n or(\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.reservationId),\n ),\n ),\n ),\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n ),\n ),\n ),\n ),\n and(\n isNull(providerRunners.workspaceId),\n isNotNull(providerRunners.intendedReservationId),\n exists(\n tx\n .select({id: reservations.id})\n .from(reservations)\n .where(\n and(\n eq(reservations.workspaceId, params.workspaceId),\n eq(reservations.provisionerId, params.provisionerId),\n eq(reservations.id, providerRunners.intendedReservationId),\n ),\n ),\n ),\n ),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .for('update');\n\n if (rows.length === 0) return 0;\n\n const updated = await tx\n .update(providerRunners)\n .set({\n intendedReservationId: null,\n reservationReleasedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n rows.map((row) => row.id),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .returning({id: providerRunners.id});\n\n const releasesByReservationId = new Map<\n string,\n {workspaceId: string; reservationId: string; count: number}\n >();\n const updatedIds = new Set(updated.map((row) => row.id));\n for (const row of rows) {\n if (!updatedIds.has(row.id)) continue;\n if (!row.releaseReservationId || !row.releaseReservationWorkspaceId) continue;\n const key = `${row.releaseReservationWorkspaceId}:${row.releaseReservationId}`;\n const release = releasesByReservationId.get(key) ?? {\n workspaceId: row.releaseReservationWorkspaceId,\n reservationId: row.releaseReservationId,\n count: 0,\n };\n release.count += 1;\n releasesByReservationId.set(key, release);\n }\n\n if (releasesByReservationId.size === 0) return 0;\n\n let released = 0;\n for (const release of releasesByReservationId.values()) {\n released += await releaseReservationUnits(tx, {\n workspaceId: release.workspaceId,\n provisionerId: params.provisionerId,\n releases: [{reservationId: release.reservationId, count: release.count}],\n });\n }\n return released;\n}\n\nfunction staleRunnerInstanceCutoff(thresholdSeconds: number): SQL {\n return sql`now() - (${thresholdSeconds} || ' seconds')::interval`;\n}\n\nfunction staleRunnerInstanceWhere(tx: Tx, cutoff: SQL): SQL<boolean> {\n return and(\n inArray(providerRunners.state, activeStates),\n lt(providerRunners.reportedAt, cutoff),\n lt(providerRunners.updatedAt, cutoff),\n exists(\n tx\n .select({id: provisionerTokens.id})\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, providerRunners.provisionerId),\n or(isNull(provisionerTokens.lastSeenAt), lt(provisionerTokens.lastSeenAt, cutoff)),\n ),\n ),\n ),\n notExists(\n tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, providerRunners.workspaceId),\n eq(runningJobExecutions.provisionerId, providerRunners.provisionerId),\n eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId),\n ),\n ),\n ),\n notExists(\n tx\n .select({id: runnerSessions.id})\n .from(runnerSessions)\n .where(\n and(\n eq(runnerSessions.workspaceId, providerRunners.workspaceId),\n eq(runnerSessions.provisionerId, providerRunners.provisionerId),\n eq(runnerSessions.providerRunnerId, providerRunners.providerRunnerId),\n sql`${runnerSessions.updatedAt} >= ${cutoff}`,\n ),\n ),\n ),\n ) as SQL<boolean>;\n}\n\nfunction groupRunnerInstanceIds(\n rows: Array<{\n workspaceId: string | null;\n provisionerId: string;\n providerRunnerId: string | null;\n }>,\n): Array<{workspaceId: string | null; provisionerId: string; providerRunnerIds: string[]}> {\n const groups = new Map<\n string,\n {workspaceId: string | null; provisionerId: string; providerRunnerIds: string[]}\n >();\n for (const row of rows) {\n if (!row.providerRunnerId) continue;\n const key = `${row.workspaceId ?? ''}:${row.provisionerId}`;\n const group = groups.get(key) ?? {\n workspaceId: row.workspaceId,\n provisionerId: row.provisionerId,\n providerRunnerIds: [],\n };\n group.providerRunnerIds.push(row.providerRunnerId);\n groups.set(key, group);\n }\n return [...groups.values()];\n}\n\nasync function hydrateRunnerSessionIdsFromConsumedTokens(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportRow[],\n): Promise<RunnerInstanceReportRow[]> {\n if (!params.workspaceId) return events;\n const providerRunnerIds = [...new Set(events.map((event) => event.providerRunnerId))];\n if (providerRunnerIds.length === 0) return events;\n\n const tokenRows = await tx\n .select({\n providerRunnerId: ephemeralRegistrationTokens.providerRunnerId,\n consumedSessionId: ephemeralRegistrationTokens.consumedSessionId,\n })\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n inArray(ephemeralRegistrationTokens.providerRunnerId, providerRunnerIds),\n isNotNull(ephemeralRegistrationTokens.consumedSessionId),\n ),\n )\n .orderBy(\n desc(ephemeralRegistrationTokens.consumedAt),\n desc(ephemeralRegistrationTokens.createdAt),\n );\n\n const consumedSessionIdsByRunnerInstanceId = new Map<string, string>();\n for (const row of tokenRows) {\n if (!row.consumedSessionId) continue;\n if (consumedSessionIdsByRunnerInstanceId.has(row.providerRunnerId)) continue;\n consumedSessionIdsByRunnerInstanceId.set(row.providerRunnerId, row.consumedSessionId);\n }\n\n if (consumedSessionIdsByRunnerInstanceId.size === 0) return events;\n\n return events.map((event) => {\n const consumedSessionId = consumedSessionIdsByRunnerInstanceId.get(event.providerRunnerId);\n if (!consumedSessionId || event.runnerSessionId === consumedSessionId) return event;\n return {...event, runnerSessionId: consumedSessionId};\n });\n}\n\nfunction aggregateEvents(\n events: RunnerInstanceReportEvent[],\n receivedAt: Date,\n): RunnerInstanceReportRow[] {\n const byRunnerInstanceId = new Map<string, RunnerInstanceReportRow>();\n for (const rawEvent of events) {\n const event = toRunnerInstanceReportRow(rawEvent, receivedAt);\n const existing = byRunnerInstanceId.get(event.providerRunnerId);\n if (existing) mergeMilestones(existing, event);\n if (!existing || compareRunnerInstanceReportEvents(event, existing) > 0) {\n byRunnerInstanceId.set(\n event.providerRunnerId,\n existing ? mergeProjectionMetadata(event, existing) : event,\n );\n }\n }\n return [...byRunnerInstanceId.values()];\n}\n\nfunction toRunnerInstanceReportRow(\n event: RunnerInstanceReportEvent,\n receivedAt: Date,\n): RunnerInstanceReportRow {\n const reportedAt = event.reportedAt > receivedAt ? receivedAt : event.reportedAt;\n return {\n ...event,\n reportedAt,\n startedAt: event.state === 'running' ? reportedAt : null,\n stoppingAt: event.state === 'stopping' ? reportedAt : null,\n stoppedAt: event.state === 'stopped' ? reportedAt : null,\n failedAt: event.state === 'failed' ? reportedAt : null,\n terminatedAt: event.state === 'terminated' ? reportedAt : null,\n };\n}\n\nfunction mergeMilestones(target: RunnerInstanceReportRow, source: RunnerInstanceReportRow) {\n target.startedAt = earliestDate(target.startedAt, source.startedAt);\n target.stoppingAt = earliestDate(target.stoppingAt, source.stoppingAt);\n target.stoppedAt = earliestDate(target.stoppedAt, source.stoppedAt);\n target.failedAt = earliestDate(target.failedAt, source.failedAt);\n target.terminatedAt = earliestDate(target.terminatedAt, source.terminatedAt);\n}\n\nfunction mergeProjectionMetadata(\n event: RunnerInstanceReportRow,\n existing: RunnerInstanceReportRow,\n): RunnerInstanceReportRow {\n return {\n ...event,\n reservationId: event.reservationId ?? existing.reservationId,\n templateKey: event.templateKey ?? existing.templateKey,\n runnerSessionId: event.runnerSessionId ?? existing.runnerSessionId,\n providerKind: event.providerKind ?? existing.providerKind,\n ...pickMilestones(existing),\n };\n}\n\nfunction pickMilestones(event: RunnerInstanceReportRow) {\n return {\n startedAt: event.startedAt,\n stoppingAt: event.stoppingAt,\n stoppedAt: event.stoppedAt,\n failedAt: event.failedAt,\n terminatedAt: event.terminatedAt,\n };\n}\n\nfunction earliestDate(a: Date | null, b: Date | null): Date | null {\n if (!a) return b;\n if (!b) return a;\n return a < b ? a : b;\n}\n\nfunction compareRunnerInstanceReportEvents(\n a: RunnerInstanceReportEvent,\n b: RunnerInstanceReportEvent,\n): number {\n const timeDelta = a.reportedAt.getTime() - b.reportedAt.getTime();\n const rankDelta = getRunnerInstanceStateRank(a.state) - getRunnerInstanceStateRank(b.state);\n if (rankDelta !== 0) return rankDelta;\n return timeDelta;\n}\n\nfunction getRunnerInstanceStateRank(state: RunnerInstanceState): number {\n switch (state) {\n case 'starting':\n return 1;\n case 'running':\n return 2;\n case 'stopping':\n return 3;\n case 'stopped':\n return 4;\n case 'failed':\n return 5;\n case 'terminated':\n return 6;\n }\n}\n\nfunction providerRunnerStateRank(state: SQL | typeof providerRunners.state): SQL<number> {\n return sql<number>`\n CASE ${state}\n WHEN 'starting' THEN 1\n WHEN 'running' THEN 2\n WHEN 'stopping' THEN 3\n WHEN 'stopped' THEN 4\n WHEN 'failed' THEN 5\n WHEN 'terminated' THEN 6\n ELSE 0\n END\n `;\n}\n\nfunction providerRunnerProjectionUpdateCondition(): SQL<boolean> {\n return sql<boolean>`\n ${providerRunnerStateRank(sql`excluded.state`)} > ${providerRunnerStateRank(providerRunners.state)}\n OR (\n ${providerRunnerStateRank(sql`excluded.state`)} = ${providerRunnerStateRank(providerRunners.state)}\n AND excluded.reported_at >= ${providerRunners.reportedAt}\n )\n `;\n}\n\nfunction providerRunnerMilestoneUpdateCondition(): SQL<boolean> {\n return sql<boolean>`\n ${milestoneNeedsUpdate(providerRunners.startedAt, sql`excluded.started_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.stoppingAt, sql`excluded.stopping_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.stoppedAt, sql`excluded.stopped_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.failedAt, sql`excluded.failed_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.terminatedAt, sql`excluded.terminated_at`)}\n `;\n}\n\nfunction milestoneNeedsUpdate(\n current: SQL | RunnerInstanceMilestoneColumn,\n incoming: SQL,\n): SQL<boolean> {\n return sql<boolean>`${incoming} IS NOT NULL AND (${current} IS NULL OR ${incoming} < ${current})`;\n}\n\nfunction firstObservedAt(current: SQL | RunnerInstanceMilestoneColumn, incoming: SQL) {\n return sql`\n CASE\n WHEN ${incoming} IS NULL THEN ${current}\n WHEN ${current} IS NULL THEN ${incoming}\n ELSE least(${current}, ${incoming})\n END\n `;\n}\n\nexport function isTerminalState(state: RunnerInstanceState): boolean {\n return terminalStates.includes(state as (typeof terminalStates)[number]);\n}\n\nfunction isDivergenceCountState(\n state: RunnerInstanceState,\n): state is (typeof divergenceCountStates)[number] {\n return divergenceCountStates.includes(state as (typeof divergenceCountStates)[number]);\n}\n"],"names":["logger","and","asc","desc","eq","exists","gt","inArray","isNotNull","isNull","lt","notExists","notInArray","or","sql","alias","config","sanitizeRunnerLabels","recordRunnerReservationCapacityFailure","db","listRunningJobExecutionsByRunnerInstanceTx","lockRunnerReservationAdvisoryKeysTx","releaseReservationUnits","validateRunnerReservationCapacityTx","terminalStates","ephemeralRegistrationTokens","provisionerTokens","reservations","runnerControlSessions","providerRunners","toRunnerInstance","runnerSessions","runningJobExecutions","activeStates","divergenceCountStates","attachRunnerInstanceProviderId","params","updated","update","set","providerRunnerId","updatedAt","where","id","runnerInstanceId","provisionerId","state","returning","length","reportRunnerInstances","events","accepted","reservationsReleased","terminateIntentsHonored","transaction","tx","receivedAt","Date","aggregatedEvents","aggregateEvents","hasTerminalEvent","some","event","isTerminalState","execute","workspaceId","hydrateRunnerSessionIdsFromConsumedTokens","reservationSafeEvents","guardReportedReservationIdsTx","listTerminateIntentsHonoredByTerminatedReportsTx","values","map","reservationId","templateKey","labels","scope","logLevel","source","reason","runnerSessionId","providerKind","reportedAt","startedAt","stoppingAt","stoppedAt","failedAt","terminatedAt","insert","onConflictDoUpdate","target","targetWhere","providerRunnerProjectionUpdateCondition","firstObservedAt","setWhere","providerRunnerMilestoneUpdateCondition","releaseTerminalRunnerInstanceReservations","reservationIds","Set","flatMap","sort","providerRunnerIds","existingRows","select","intendedReservationId","reservationReleasedAt","from","for","existingByProviderRunnerId","Map","row","candidateReservationByProviderRunnerId","existing","get","validation","requests","count","advisoryLocksHeld","unavailableByReservation","remainingAcceptedByReservation","acceptedByReservation","matchesExistingReservation","undefined","remaining","listActiveRunnerInstanceCountsByTemplateTx","rows","groupBy","isDivergenceCountState","countStaleEnrolledRunnerInstances","staleRunnerInstanceCutoff","graceSeconds","closedAt","expiresAt","listActiveRunnerInstances","windowSeconds","orderBy","limit","listProvisionerTerminateIntents","listProvisionerTerminateIntentRowsTx","provisionerTerminateIntentsQuery","truncated","returnedRows","slice","warn","returnedCount","activationTimeoutRunnerIds","toRunnerInstanceTerminateIntent","activationTimeoutRetry","newerRunningJobExecutions","latestCancelledJob","cancellationRequestedAt","jobExecutionId","activationTimeout","launchKind","createdAt","RUNNER_DEMAND_ACTIVATION_TIMEOUT_SECONDS","terminatedRunnerInstanceIds","filter","reconcileRunnerInstances","observedRunnerInstanceIds","absentIds","staleAbsentRows","terminateGraceSeconds","releaseTerminalRunnerInstanceReservationsByIds","observedRows","boundJobExecutions","boundJobExecutionsByRunnerInstanceId","jobExecution","reapStaleRunnerInstances","cutoff","thresholdSeconds","candidateRows","staleRunnerInstanceWhere","reaped","workspaceIds","updatedRows","group","groupRunnerInstanceIds","requireUnlinkedSession","terminalEvents","reservationWorkspacePredicate","releaseReservationId","releaseReservationWorkspaceId","releasesByReservationId","updatedIds","has","key","release","size","released","releases","lastSeenAt","groups","push","tokenRows","consumedSessionId","consumedAt","consumedSessionIdsByRunnerInstanceId","byRunnerInstanceId","rawEvent","toRunnerInstanceReportRow","mergeMilestones","compareRunnerInstanceReportEvents","mergeProjectionMetadata","earliestDate","pickMilestones","a","b","timeDelta","getTime","rankDelta","getRunnerInstanceStateRank","providerRunnerStateRank","milestoneNeedsUpdate","current","incoming","includes"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const terminalStates: readonly ["stopped", "failed", "terminated"];
2
+ //# sourceMappingURL=runner-states.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner-states.d.ts","sourceRoot":"","sources":["../../src/db/runner-states.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,8CAIwB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export const terminalStates = [
2
+ 'stopped',
3
+ 'failed',
4
+ 'terminated'
5
+ ];
6
+
7
+ //# sourceMappingURL=runner-states.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/db/runner-states.ts"],"sourcesContent":["import type {RunnerInstanceState} from '#core/entities/runner-instance.js';\n\nexport const terminalStates = [\n 'stopped',\n 'failed',\n 'terminated',\n] as const satisfies readonly RunnerInstanceState[];\n"],"names":["terminalStates"],"mappings":"AAEA,OAAO,MAAMA,iBAAiB;IAC5B;IACA;IACA;CACD,CAAmD"}
@@ -1,4 +1,5 @@
1
1
  import type { Reservation } from '#core/entities/reservation.js';
2
+ export declare const reservationKindEnum: import("drizzle-orm/pg-core").PgEnum<["bound", "launch"]>;
2
3
  export declare const reservations: import("drizzle-orm/pg-core").PgTableWithColumns<{
3
4
  name: "reservations";
4
5
  schema: undefined;
@@ -114,6 +115,23 @@ export declare const reservations: import("drizzle-orm/pg-core").PgTableWithColu
114
115
  identity: undefined;
115
116
  generated: undefined;
116
117
  }, {}, {}>;
118
+ kind: import("drizzle-orm/pg-core").PgColumn<{
119
+ name: "kind";
120
+ tableName: "reservations";
121
+ dataType: "string";
122
+ columnType: "PgEnumColumn";
123
+ data: "bound" | "launch";
124
+ driverParam: string;
125
+ notNull: true;
126
+ hasDefault: true;
127
+ isPrimaryKey: false;
128
+ isAutoincrement: false;
129
+ hasRuntimeDefault: false;
130
+ enumValues: ["bound", "launch"];
131
+ baseColumn: never;
132
+ identity: undefined;
133
+ generated: undefined;
134
+ }, {}, {}>;
117
135
  createdAt: import("drizzle-orm/pg-core").PgColumn<{
118
136
  name: "created_at";
119
137
  tableName: "reservations";
@@ -1 +1 @@
1
- {"version":3,"file":"reservations.d.ts","sourceRoot":"","sources":["../../../src/db/schema/reservations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,+BAA+B,CAAC;AAG/D,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAC7D,MAAM,MAAM,mBAAmB,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAEnE,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,CAU7D"}
1
+ {"version":3,"file":"reservations.d.ts","sourceRoot":"","sources":["../../../src/db/schema/reservations.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,+BAA+B,CAAC;AAG/D,eAAO,MAAM,mBAAmB,2DAA0D,CAAC;AAE3F,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBxB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAC7D,MAAM,MAAM,mBAAmB,GAAG,OAAO,YAAY,CAAC,YAAY,CAAC;AAEnE,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,WAAW,CAW7D"}