@shipfox/api-runners 12.4.0 → 12.5.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 (55) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +21 -0
  3. package/dist/core/errors.d.ts +5 -1
  4. package/dist/core/errors.d.ts.map +1 -1
  5. package/dist/core/errors.js +9 -2
  6. package/dist/core/errors.js.map +1 -1
  7. package/dist/core/runner-control-sessions.d.ts.map +1 -1
  8. package/dist/core/runner-control-sessions.js +62 -12
  9. package/dist/core/runner-control-sessions.js.map +1 -1
  10. package/dist/db/job-executions.d.ts.map +1 -1
  11. package/dist/db/job-executions.js +35 -4
  12. package/dist/db/job-executions.js.map +1 -1
  13. package/dist/db/runner-assignments.d.ts +8 -1
  14. package/dist/db/runner-assignments.d.ts.map +1 -1
  15. package/dist/db/runner-assignments.js +57 -10
  16. package/dist/db/runner-assignments.js.map +1 -1
  17. package/dist/db/runner-instances.d.ts +9 -0
  18. package/dist/db/runner-instances.d.ts.map +1 -1
  19. package/dist/db/runner-instances.js +43 -0
  20. package/dist/db/runner-instances.js.map +1 -1
  21. package/dist/db/runner-sessions.d.ts.map +1 -1
  22. package/dist/db/runner-sessions.js +14 -1
  23. package/dist/db/runner-sessions.js.map +1 -1
  24. package/dist/metrics/index.d.ts +2 -2
  25. package/dist/metrics/index.d.ts.map +1 -1
  26. package/dist/metrics/index.js +1 -1
  27. package/dist/metrics/index.js.map +1 -1
  28. package/dist/metrics/instance.d.ts +48 -0
  29. package/dist/metrics/instance.d.ts.map +1 -1
  30. package/dist/metrics/instance.js +138 -1
  31. package/dist/metrics/instance.js.map +1 -1
  32. package/dist/metrics/service.d.ts.map +1 -1
  33. package/dist/metrics/service.js +25 -4
  34. package/dist/metrics/service.js.map +1 -1
  35. package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -1
  36. package/dist/presentation/routes/assign-runner-instances.js +7 -1
  37. package/dist/presentation/routes/assign-runner-instances.js.map +1 -1
  38. package/dist/tsconfig.test.tsbuildinfo +1 -1
  39. package/package.json +2 -2
  40. package/src/core/errors.ts +30 -1
  41. package/src/core/runner-control-sessions.test.ts +71 -0
  42. package/src/core/runner-control-sessions.ts +79 -10
  43. package/src/db/job-executions.test.ts +98 -12
  44. package/src/db/job-executions.ts +52 -4
  45. package/src/db/runner-assignments.ts +67 -16
  46. package/src/db/runner-instances.test.ts +92 -0
  47. package/src/db/runner-instances.ts +74 -0
  48. package/src/db/runner-sessions.ts +19 -1
  49. package/src/metrics/index.ts +14 -0
  50. package/src/metrics/instance.test.ts +118 -0
  51. package/src/metrics/instance.ts +188 -1
  52. package/src/metrics/service.test.ts +38 -0
  53. package/src/metrics/service.ts +55 -8
  54. package/src/presentation/routes/assign-runner-instances.ts +8 -0
  55. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1,6 +1,6 @@
1
1
  $ shipfox-swc && shipfox-temporal-bundle dist/temporal/workflows/index.js
2
- Successfully compiled: 104 files with swc (886.73ms)
3
- 2026-08-08T09:17:02.061Z [INFO] asset workflow-bundle-0c3da2487e29e352d64e.js 3.17 MiB [emitted] [immutable] (name: main)
2
+ Successfully compiled: 104 files with swc (724.42ms)
3
+ 2026-08-09T17:50:59.992Z [INFO] asset workflow-bundle-0c3da2487e29e352d64e.js 3.17 MiB [emitted] [immutable] (name: main)
4
4
  orphan modules 33.5 KiB [orphan] 21 modules
5
5
  runtime modules 1.13 KiB 5 modules
6
6
  modules by path ../../../node_modules/.pnpm/ 970 KiB 196 modules
@@ -14,6 +14,6 @@ optional modules 30 bytes [optional]
14
14
  __temporal_custom_payload_converter (ignored) 15 bytes [optional] [built] [code generated]
15
15
  __temporal_custom_failure_converter (ignored) 15 bytes [optional] [built] [code generated]
16
16
  ../../shared/node/temporal/dist/workflow-error-interceptor.js 1.21 KiB [built] [code generated]
17
- webpack 5.107.2 compiled successfully in 12068 ms
18
- 2026-08-08T09:17:02.096Z [INFO] Workflow bundle created { size: '3.17MB' }
17
+ webpack 5.107.2 compiled successfully in 11865 ms
18
+ 2026-08-09T17:51:00.034Z [INFO] Workflow bundle created { size: '3.17MB' }
19
19
  /home/runner/work/shipfox/shipfox/libs/api/runners/dist/temporal/workflows/index.js: 3326598 bytes
package/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # @shipfox/api-runners
2
2
 
3
+ ## 12.5.0
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [5b1838c]
8
+ - @shipfox/api-workflows-dto@12.5.0
9
+
10
+ ## 12.4.1
11
+
12
+ ### Patch Changes
13
+
14
+ - f8eb3b5: Record job execution queue-time histograms for runner SLI dashboards.
15
+ - 38e0acb: Downgrades expected runner assignment retries to debug logging. Adds the
16
+ `runners_provider_runner_created_to_control_session`,
17
+ `runners_provider_runner_control_session_to_assignment`,
18
+ `runners_provider_runner_assignment_to_activation`,
19
+ `runners_provider_runner_activation_to_first_claim`,
20
+ `runners_provider_runner_assignment_rejected`,
21
+ `runners_provider_runner_by_phase`, and
22
+ `runners_provider_runner_by_phase_oldest_age` metrics.
23
+
3
24
  ## 12.4.0
4
25
 
5
26
  ### Minor Changes
@@ -50,14 +50,18 @@ export declare class ReservationExpiredError extends Error {
50
50
  readonly reservationId: string;
51
51
  constructor(reservationId: string);
52
52
  }
53
+ export type RunnerInstanceNotAssignableReason = 'runner-not-found' | 'runner-not-running' | 'provider-identity-missing' | 'control-session-not-active' | 'labels-mismatch' | 'capacity-exhausted';
54
+ export type RunnerAssignmentRejectionReason = 'reservation-not-found' | 'reservation-expired' | 'already-assigned' | RunnerInstanceNotAssignableReason;
53
55
  export declare class RunnerInstanceNotAssignableError extends Error {
54
56
  readonly runnerInstanceId: string;
55
- constructor(runnerInstanceId: string);
57
+ readonly reason: RunnerInstanceNotAssignableReason;
58
+ constructor(runnerInstanceId: string, reason: RunnerInstanceNotAssignableReason);
56
59
  }
57
60
  export declare class RunnerInstanceAlreadyAssignedError extends Error {
58
61
  readonly runnerInstanceId: string;
59
62
  constructor(runnerInstanceId: string);
60
63
  }
64
+ export declare function getRunnerAssignmentRejectionReason(error: unknown): RunnerAssignmentRejectionReason | null;
61
65
  export declare class ReservationAlreadyAssignedError extends Error {
62
66
  readonly reservationId: string;
63
67
  constructor(reservationId: string);
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,YAAY,cAAc,EAAE,MAAM,EAGjC;CACF;AAED,qBAAa,oCAAqC,SAAQ,KAAK;IAC7D,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAED,qBAAa,wCAAyC,SAAQ,KAAK;IACjE,cAGC;CACF;AAED,qBAAa,iDAAkD,SAAQ,KAAK;IAC1E,cAGC;CACF;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,cAGC;CACF;AAED,qBAAa,yBAA0B,SAAQ,KAAK;aACtB,MAAM,EAAE,MAAM,EAAE;IAA5C,YAA4B,MAAM,EAAE,MAAM,EAAE,EAK3C;CACF;AAED,qBAAa,wBAAyB,SAAQ,KAAK;IACjD,cAGC;CACF;AAED,qBAAa,8BAA+B,SAAQ,KAAK;aAC3B,gBAAgB,EAAE,MAAM;IAApD,YAA4B,gBAAgB,EAAE,MAAM,EAGnD;CACF;AAED,qBAAa,6BAA8B,SAAQ,KAAK;aAC1B,gBAAgB,EAAE,MAAM;IAApD,YAA4B,gBAAgB,EAAE,MAAM,EAGnD;CACF;AAED,qBAAa,uCAAwC,SAAQ,KAAK;aAE9C,gBAAgB,EAAE,MAAM;aACxB,WAAW,EAAE,MAAM;IAFrC,YACkB,gBAAgB,EAAE,MAAM,EACxB,WAAW,EAAE,MAAM,EAMpC;CACF;AAED,qBAAa,2CAA4C,SAAQ,KAAK;aAElD,WAAW,EAAE,MAAM;aACnB,aAAa,EAAE,MAAM;aACrB,gBAAgB,EAAE,MAAM;IAH1C,YACkB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,EACrB,gBAAgB,EAAE,MAAM,EAMzC;CACF;AAED,qBAAa,wBAAyB,SAAQ,KAAK;aACrB,aAAa,EAAE,MAAM;IAAjD,YAA4B,aAAa,EAAE,MAAM,EAGhD;CACF;AAED,qBAAa,uBAAwB,SAAQ,KAAK;aACpB,aAAa,EAAE,MAAM;IAAjD,YAA4B,aAAa,EAAE,MAAM,EAGhD;CACF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;aAC7B,gBAAgB,EAAE,MAAM;IAApD,YAA4B,gBAAgB,EAAE,MAAM,EAGnD;CACF;AACD,qBAAa,kCAAmC,SAAQ,KAAK;aAC/B,gBAAgB,EAAE,MAAM;IAApD,YAA4B,gBAAgB,EAAE,MAAM,EAGnD;CACF;AACD,qBAAa,+BAAgC,SAAQ,KAAK;aAC5B,aAAa,EAAE,MAAM;IAAjD,YAA4B,aAAa,EAAE,MAAM,EAGhD;CACF;AAED,qBAAa,mCAAoC,SAAQ,KAAK;aAE1C,SAAS,EAAE,MAAM;aACjB,GAAG,EAAE,MAAM;IAF7B,YACkB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EAM5B;CACF;AAED,qBAAa,6CAA8C,SAAQ,KAAK;aAEpD,SAAS,EAAE,MAAM;aACjB,gBAAgB,EAAE,MAAM;aACxB,aAAa,EAAE,MAAM;IAHvC,YACkB,SAAS,EAAE,MAAM,EACjB,gBAAgB,EAAE,MAAM,EACxB,aAAa,GAAE,MAAU,EAM1C;CACF;AAED,qBAAa,2CAA4C,SAAQ,KAAK;aACxC,iBAAiB,EAAE,MAAM,EAAE;IAAvD,YAA4B,iBAAiB,EAAE,MAAM,EAAE,EAKtD;CACF;AAED,qBAAa,2BAA4B,SAAQ,KAAK;aACxB,eAAe,EAAE,MAAM;IAAnD,YAA4B,eAAe,EAAE,MAAM,EAGlD;CACF"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/core/errors.ts"],"names":[],"mappings":"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"}
@@ -83,8 +83,8 @@ export class ReservationExpiredError extends Error {
83
83
  }
84
84
  }
85
85
  export class RunnerInstanceNotAssignableError extends Error {
86
- constructor(runnerInstanceId){
87
- super(`Runner instance cannot be assigned: ${runnerInstanceId}`), this.runnerInstanceId = runnerInstanceId;
86
+ constructor(runnerInstanceId, reason){
87
+ super(`Runner instance cannot be assigned: ${runnerInstanceId}`), this.runnerInstanceId = runnerInstanceId, this.reason = reason;
88
88
  this.name = 'RunnerInstanceNotAssignableError';
89
89
  }
90
90
  }
@@ -94,6 +94,13 @@ export class RunnerInstanceAlreadyAssignedError extends Error {
94
94
  this.name = 'RunnerInstanceAlreadyAssignedError';
95
95
  }
96
96
  }
97
+ export function getRunnerAssignmentRejectionReason(error) {
98
+ if (error instanceof ReservationNotFoundError) return 'reservation-not-found';
99
+ if (error instanceof ReservationExpiredError) return 'reservation-expired';
100
+ if (error instanceof RunnerInstanceAlreadyAssignedError) return 'already-assigned';
101
+ if (error instanceof RunnerInstanceNotAssignableError) return error.reason;
102
+ return null;
103
+ }
97
104
  export class ReservationAlreadyAssignedError extends Error {
98
105
  constructor(reservationId){
99
106
  super(`Reservation is already assigned: ${reservationId}`), this.reservationId = reservationId;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class RunningJobExecutionNotFoundError extends Error {\n constructor(jobExecutionId: string) {\n super(`Running job execution not found: ${jobExecutionId}`);\n this.name = 'RunningJobExecutionNotFoundError';\n }\n}\n\nexport class ManualRegistrationTokenNotFoundError extends Error {\n constructor(tokenId: string) {\n super(`Manual registration token not found: ${tokenId}`);\n this.name = 'ManualRegistrationTokenNotFoundError';\n }\n}\n\nexport class ProvisionerTokenNotFoundError extends Error {\n constructor(tokenId: string) {\n super(`Provisioner token not found: ${tokenId}`);\n this.name = 'ProvisionerTokenNotFoundError';\n }\n}\n\nexport class ProvisionerAdminIdempotencyKeyReuseError extends Error {\n constructor() {\n super('Idempotency-Key was already used for a different provisioner token command');\n this.name = 'ProvisionerAdminIdempotencyKeyReuseError';\n }\n}\n\nexport class ProvisionerAdminIdempotencyReplayUnavailableError extends Error {\n constructor() {\n super('Idempotency-Key replay cannot reproduce the original provisioner token');\n this.name = 'ProvisionerAdminIdempotencyReplayUnavailableError';\n }\n}\n\nexport class EmptyRunnerLabelsError extends Error {\n constructor() {\n super('Runner labels cannot be empty');\n this.name = 'EmptyRunnerLabelsError';\n }\n}\n\nexport class RunnerLabelsReservedError extends Error {\n constructor(public readonly labels: string[]) {\n super(\n `All supplied runner labels are reserved for installation-scope provisioners: ${labels.join(', ')}`,\n );\n this.name = 'RunnerLabelsReservedError';\n }\n}\n\nexport class EmptyRequiredLabelsError extends Error {\n constructor() {\n super('Required labels cannot be empty');\n this.name = 'EmptyRequiredLabelsError';\n }\n}\n\nexport class RegistrationTokenConsumedError extends Error {\n constructor(public readonly ephemeralTokenId: string) {\n super(`Ephemeral registration token has already been consumed: ${ephemeralTokenId}`);\n this.name = 'RegistrationTokenConsumedError';\n }\n}\n\nexport class RegistrationTokenExpiredError extends Error {\n constructor(public readonly ephemeralTokenId: string) {\n super(`Ephemeral registration token has expired: ${ephemeralTokenId}`);\n this.name = 'RegistrationTokenExpiredError';\n }\n}\n\nexport class RegistrationTokenWorkspaceMismatchError extends Error {\n constructor(\n public readonly ephemeralTokenId: string,\n public readonly workspaceId: string,\n ) {\n super(\n `Ephemeral registration token ${ephemeralTokenId} does not belong to workspace ${workspaceId}`,\n );\n this.name = 'RegistrationTokenWorkspaceMismatchError';\n }\n}\n\nexport class ActiveEphemeralRegistrationTokenExistsError extends Error {\n constructor(\n public readonly workspaceId: string,\n public readonly provisionerId: string,\n public readonly providerRunnerId: string,\n ) {\n super(\n `Active ephemeral registration token already exists for provisioned runner ${providerRunnerId} in workspace ${workspaceId}`,\n );\n this.name = 'ActiveEphemeralRegistrationTokenExistsError';\n }\n}\n\nexport class ReservationNotFoundError extends Error {\n constructor(public readonly reservationId: string) {\n super(`Reservation not found: ${reservationId}`);\n this.name = 'ReservationNotFoundError';\n }\n}\n\nexport class ReservationExpiredError extends Error {\n constructor(public readonly reservationId: string) {\n super(`Reservation has expired: ${reservationId}`);\n this.name = 'ReservationExpiredError';\n }\n}\n\nexport class RunnerInstanceNotAssignableError extends Error {\n constructor(public readonly runnerInstanceId: string) {\n super(`Runner instance cannot be assigned: ${runnerInstanceId}`);\n this.name = 'RunnerInstanceNotAssignableError';\n }\n}\nexport class RunnerInstanceAlreadyAssignedError extends Error {\n constructor(public readonly runnerInstanceId: string) {\n super(`Runner instance is already assigned: ${runnerInstanceId}`);\n this.name = 'RunnerInstanceAlreadyAssignedError';\n }\n}\nexport class ReservationAlreadyAssignedError extends Error {\n constructor(public readonly reservationId: string) {\n super(`Reservation is already assigned: ${reservationId}`);\n this.name = 'ReservationAlreadyAssignedError';\n }\n}\n\nexport class RegistrationTokenBatchTooLargeError extends Error {\n constructor(\n public readonly requested: number,\n public readonly max: number,\n ) {\n super(\n `Registration token batch requested ${requested} provisioned runners, exceeding max ${max}`,\n );\n this.name = 'RegistrationTokenBatchTooLargeError';\n }\n}\n\nexport class RegistrationTokenBatchExceedsReservationError extends Error {\n constructor(\n public readonly requested: number,\n public readonly reservationCount: number,\n public readonly alreadyMinted: number = 0,\n ) {\n super(\n `Registration token batch requested ${requested} provisioned runners with ${alreadyMinted} already minted, exceeding reservation count ${reservationCount}`,\n );\n this.name = 'RegistrationTokenBatchExceedsReservationError';\n }\n}\n\nexport class ActiveEphemeralRegistrationTokensExistError extends Error {\n constructor(public readonly providerRunnerIds: string[]) {\n super(\n `Active ephemeral registration tokens already exist for provisioned runners: ${providerRunnerIds.join(', ')}`,\n );\n this.name = 'ActiveEphemeralRegistrationTokensExistError';\n }\n}\n\nexport class RunnerSessionExhaustedError extends Error {\n constructor(public readonly runnerSessionId: string) {\n super(`Runner session claim limit exhausted: ${runnerSessionId}`);\n this.name = 'RunnerSessionExhaustedError';\n }\n}\n"],"names":["RunningJobExecutionNotFoundError","Error","jobExecutionId","name","ManualRegistrationTokenNotFoundError","tokenId","ProvisionerTokenNotFoundError","ProvisionerAdminIdempotencyKeyReuseError","ProvisionerAdminIdempotencyReplayUnavailableError","EmptyRunnerLabelsError","RunnerLabelsReservedError","labels","join","EmptyRequiredLabelsError","RegistrationTokenConsumedError","ephemeralTokenId","RegistrationTokenExpiredError","RegistrationTokenWorkspaceMismatchError","workspaceId","ActiveEphemeralRegistrationTokenExistsError","provisionerId","providerRunnerId","ReservationNotFoundError","reservationId","ReservationExpiredError","RunnerInstanceNotAssignableError","runnerInstanceId","RunnerInstanceAlreadyAssignedError","ReservationAlreadyAssignedError","RegistrationTokenBatchTooLargeError","requested","max","RegistrationTokenBatchExceedsReservationError","reservationCount","alreadyMinted","ActiveEphemeralRegistrationTokensExistError","providerRunnerIds","RunnerSessionExhaustedError","runnerSessionId"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/errors.ts"],"sourcesContent":["export class RunningJobExecutionNotFoundError extends Error {\n constructor(jobExecutionId: string) {\n super(`Running job execution not found: ${jobExecutionId}`);\n this.name = 'RunningJobExecutionNotFoundError';\n }\n}\n\nexport class ManualRegistrationTokenNotFoundError extends Error {\n constructor(tokenId: string) {\n super(`Manual registration token not found: ${tokenId}`);\n this.name = 'ManualRegistrationTokenNotFoundError';\n }\n}\n\nexport class ProvisionerTokenNotFoundError extends Error {\n constructor(tokenId: string) {\n super(`Provisioner token not found: ${tokenId}`);\n this.name = 'ProvisionerTokenNotFoundError';\n }\n}\n\nexport class ProvisionerAdminIdempotencyKeyReuseError extends Error {\n constructor() {\n super('Idempotency-Key was already used for a different provisioner token command');\n this.name = 'ProvisionerAdminIdempotencyKeyReuseError';\n }\n}\n\nexport class ProvisionerAdminIdempotencyReplayUnavailableError extends Error {\n constructor() {\n super('Idempotency-Key replay cannot reproduce the original provisioner token');\n this.name = 'ProvisionerAdminIdempotencyReplayUnavailableError';\n }\n}\n\nexport class EmptyRunnerLabelsError extends Error {\n constructor() {\n super('Runner labels cannot be empty');\n this.name = 'EmptyRunnerLabelsError';\n }\n}\n\nexport class RunnerLabelsReservedError extends Error {\n constructor(public readonly labels: string[]) {\n super(\n `All supplied runner labels are reserved for installation-scope provisioners: ${labels.join(', ')}`,\n );\n this.name = 'RunnerLabelsReservedError';\n }\n}\n\nexport class EmptyRequiredLabelsError extends Error {\n constructor() {\n super('Required labels cannot be empty');\n this.name = 'EmptyRequiredLabelsError';\n }\n}\n\nexport class RegistrationTokenConsumedError extends Error {\n constructor(public readonly ephemeralTokenId: string) {\n super(`Ephemeral registration token has already been consumed: ${ephemeralTokenId}`);\n this.name = 'RegistrationTokenConsumedError';\n }\n}\n\nexport class RegistrationTokenExpiredError extends Error {\n constructor(public readonly ephemeralTokenId: string) {\n super(`Ephemeral registration token has expired: ${ephemeralTokenId}`);\n this.name = 'RegistrationTokenExpiredError';\n }\n}\n\nexport class RegistrationTokenWorkspaceMismatchError extends Error {\n constructor(\n public readonly ephemeralTokenId: string,\n public readonly workspaceId: string,\n ) {\n super(\n `Ephemeral registration token ${ephemeralTokenId} does not belong to workspace ${workspaceId}`,\n );\n this.name = 'RegistrationTokenWorkspaceMismatchError';\n }\n}\n\nexport class ActiveEphemeralRegistrationTokenExistsError extends Error {\n constructor(\n public readonly workspaceId: string,\n public readonly provisionerId: string,\n public readonly providerRunnerId: string,\n ) {\n super(\n `Active ephemeral registration token already exists for provisioned runner ${providerRunnerId} in workspace ${workspaceId}`,\n );\n this.name = 'ActiveEphemeralRegistrationTokenExistsError';\n }\n}\n\nexport class ReservationNotFoundError extends Error {\n constructor(public readonly reservationId: string) {\n super(`Reservation not found: ${reservationId}`);\n this.name = 'ReservationNotFoundError';\n }\n}\n\nexport class ReservationExpiredError extends Error {\n constructor(public readonly reservationId: string) {\n super(`Reservation has expired: ${reservationId}`);\n this.name = 'ReservationExpiredError';\n }\n}\n\nexport type RunnerInstanceNotAssignableReason =\n | 'runner-not-found'\n | 'runner-not-running'\n | 'provider-identity-missing'\n | 'control-session-not-active'\n | 'labels-mismatch'\n | 'capacity-exhausted';\n\nexport type RunnerAssignmentRejectionReason =\n | 'reservation-not-found'\n | 'reservation-expired'\n | 'already-assigned'\n | RunnerInstanceNotAssignableReason;\n\nexport class RunnerInstanceNotAssignableError extends Error {\n constructor(\n public readonly runnerInstanceId: string,\n public readonly reason: RunnerInstanceNotAssignableReason,\n ) {\n super(`Runner instance cannot be assigned: ${runnerInstanceId}`);\n this.name = 'RunnerInstanceNotAssignableError';\n }\n}\n\nexport class RunnerInstanceAlreadyAssignedError extends Error {\n constructor(public readonly runnerInstanceId: string) {\n super(`Runner instance is already assigned: ${runnerInstanceId}`);\n this.name = 'RunnerInstanceAlreadyAssignedError';\n }\n}\n\nexport function getRunnerAssignmentRejectionReason(\n error: unknown,\n): RunnerAssignmentRejectionReason | null {\n if (error instanceof ReservationNotFoundError) return 'reservation-not-found';\n if (error instanceof ReservationExpiredError) return 'reservation-expired';\n if (error instanceof RunnerInstanceAlreadyAssignedError) return 'already-assigned';\n if (error instanceof RunnerInstanceNotAssignableError) return error.reason;\n return null;\n}\n\nexport class ReservationAlreadyAssignedError extends Error {\n constructor(public readonly reservationId: string) {\n super(`Reservation is already assigned: ${reservationId}`);\n this.name = 'ReservationAlreadyAssignedError';\n }\n}\n\nexport class RegistrationTokenBatchTooLargeError extends Error {\n constructor(\n public readonly requested: number,\n public readonly max: number,\n ) {\n super(\n `Registration token batch requested ${requested} provisioned runners, exceeding max ${max}`,\n );\n this.name = 'RegistrationTokenBatchTooLargeError';\n }\n}\n\nexport class RegistrationTokenBatchExceedsReservationError extends Error {\n constructor(\n public readonly requested: number,\n public readonly reservationCount: number,\n public readonly alreadyMinted: number = 0,\n ) {\n super(\n `Registration token batch requested ${requested} provisioned runners with ${alreadyMinted} already minted, exceeding reservation count ${reservationCount}`,\n );\n this.name = 'RegistrationTokenBatchExceedsReservationError';\n }\n}\n\nexport class ActiveEphemeralRegistrationTokensExistError extends Error {\n constructor(public readonly providerRunnerIds: string[]) {\n super(\n `Active ephemeral registration tokens already exist for provisioned runners: ${providerRunnerIds.join(', ')}`,\n );\n this.name = 'ActiveEphemeralRegistrationTokensExistError';\n }\n}\n\nexport class RunnerSessionExhaustedError extends Error {\n constructor(public readonly runnerSessionId: string) {\n super(`Runner session claim limit exhausted: ${runnerSessionId}`);\n this.name = 'RunnerSessionExhaustedError';\n }\n}\n"],"names":["RunningJobExecutionNotFoundError","Error","jobExecutionId","name","ManualRegistrationTokenNotFoundError","tokenId","ProvisionerTokenNotFoundError","ProvisionerAdminIdempotencyKeyReuseError","ProvisionerAdminIdempotencyReplayUnavailableError","EmptyRunnerLabelsError","RunnerLabelsReservedError","labels","join","EmptyRequiredLabelsError","RegistrationTokenConsumedError","ephemeralTokenId","RegistrationTokenExpiredError","RegistrationTokenWorkspaceMismatchError","workspaceId","ActiveEphemeralRegistrationTokenExistsError","provisionerId","providerRunnerId","ReservationNotFoundError","reservationId","ReservationExpiredError","RunnerInstanceNotAssignableError","runnerInstanceId","reason","RunnerInstanceAlreadyAssignedError","getRunnerAssignmentRejectionReason","error","ReservationAlreadyAssignedError","RegistrationTokenBatchTooLargeError","requested","max","RegistrationTokenBatchExceedsReservationError","reservationCount","alreadyMinted","ActiveEphemeralRegistrationTokensExistError","providerRunnerIds","RunnerSessionExhaustedError","runnerSessionId"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"runner-control-sessions.d.ts","sourceRoot":"","sources":["../../src/core/runner-control-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AA6BxE,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,cAGC;CACF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,cAGC;CACF;AAED,wBAAsB,wCAAwC,CAAC,MAAM,EAAE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,KAAK,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IACV,eAAe,EAAE,KAAK,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,sBAAsB,EAAE,OAAO,CAAC;CACjC,CAAC,CAyED;AAED,wBAAsB,4BAA4B,CAAC,MAAM,EAAE;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAC,CAAC,CA8BpF;AAED,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,MAAM;;;;eAmBjE;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4GzB;AAYD,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,OAAO,CAAC,CAcnB;AAED,wBAAsB,yBAAyB,CAAC,gBAAgB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAW9F"}
1
+ {"version":3,"file":"runner-control-sessions.d.ts","sourceRoot":"","sources":["../../src/core/runner-control-sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,yBAAyB,EAAC,MAAM,0BAA0B,CAAC;AAiCxE,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,cAGC;CACF;AAED,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,cAGC;CACF;AAED,wBAAsB,wCAAwC,CAAC,MAAM,EAAE;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,KAAK,CAAC;QACrB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KAC/B,CAAC,CAAC;IACH,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IACV,eAAe,EAAE,KAAK,CAAC;QACrB,gBAAgB,EAAE,MAAM,CAAC;QACzB,cAAc,EAAE,MAAM,CAAC;QACvB,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC,CAAC;IACH,sBAAsB,EAAE,OAAO,CAAC;CACjC,CAAC,CAyED;AAED,wBAAsB,4BAA4B,CAAC,MAAM,EAAE;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,IAAI,CAAA;CAAC,CAAC,CA+DpF;AAED,wBAAsB,2BAA2B,CAAC,QAAQ,EAAE,MAAM;;;;eAmBjE;AAED,wBAAsB,0BAA0B,CAAC,MAAM,EAAE;IACvD,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,CAAC,EAAE,yBAAyB,GAAG,IAAI,CAAC;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;CACzB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA4IzB;AAYD,wBAAsB,6BAA6B,CAAC,MAAM,EAAE;IAC1D,gBAAgB,EAAE,MAAM,CAAC;IACzB,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,GAAG,OAAO,CAAC,OAAO,CAAC,CAcnB;AAED,wBAAsB,yBAAyB,CAAC,gBAAgB,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,iBAW9F"}
@@ -2,7 +2,7 @@ import { logger } from '@shipfox/node-opentelemetry';
2
2
  import { extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken } from '@shipfox/node-tokens';
3
3
  import { and, eq, gt, isNull, notInArray, or, sql } from 'drizzle-orm';
4
4
  import { config } from '#config.js';
5
- import { ReservationExpiredError, ReservationNotFoundError, RunnerInstanceAlreadyAssignedError, RunnerInstanceNotAssignableError } from '#core/errors.js';
5
+ import { getRunnerAssignmentRejectionReason, ReservationExpiredError, ReservationNotFoundError, RunnerInstanceAlreadyAssignedError, RunnerInstanceNotAssignableError } from '#core/errors.js';
6
6
  import { sanitizeRunnerLabels } from '#core/runner-labels.js';
7
7
  import { db } from '#db/db.js';
8
8
  import { assignRunnerInstancesTx, validateRunnerReservationCapacityTx } from '#db/runner-assignments.js';
@@ -10,7 +10,7 @@ import { terminalStates } from '#db/runner-states.js';
10
10
  import { provisionerTokens } from '#db/schema/provisioner-tokens.js';
11
11
  import { runnerBootstrapTokens, runnerControlSessions } from '#db/schema/runner-control-sessions.js';
12
12
  import { providerRunners } from '#db/schema/runner-instances.js';
13
- import { recordRunnerReservationCapacityFailure, recordRunnerReservationPromotionFailure } from '#metrics/index.js';
13
+ import { recordProviderRunnerAssignmentRejected, recordProviderRunnerControlSessionToAssignment, recordProviderRunnerCreatedToControlSession, recordRunnerReservationCapacityFailure, recordRunnerReservationPromotionFailure } from '#metrics/index.js';
14
14
  import { issueRunnerActivationTokenTx } from './runner-activation.js';
15
15
  export class RunnerBootstrapTokenInvalidError extends Error {
16
16
  constructor(){
@@ -100,11 +100,17 @@ export async function createRunnerInstancesWithBootstrapTokens(params) {
100
100
  export async function exchangeRunnerBootstrapToken(params) {
101
101
  const controlSessionToken = generateOpaqueToken('runnerControlSession');
102
102
  const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);
103
- return await db().transaction(async (tx)=>{
103
+ const result = await db().transaction(async (tx)=>{
104
104
  const [bootstrap] = await tx.update(runnerBootstrapTokens).set({
105
105
  consumedAt: sql`now()`
106
106
  }).where(and(eq(runnerBootstrapTokens.hashedToken, hashOpaqueToken(params.rawToken)), isNull(runnerBootstrapTokens.consumedAt), isNull(runnerBootstrapTokens.revokedAt), gt(runnerBootstrapTokens.expiresAt, sql`now()`))).returning();
107
107
  if (!bootstrap) throw new RunnerBootstrapTokenInvalidError();
108
+ const [runner] = await tx.select({
109
+ runnerInstanceId: providerRunners.id,
110
+ createdAt: providerRunners.createdAt,
111
+ provider: providerRunners.providerKind,
112
+ launchKind: providerRunners.launchKind
113
+ }).from(providerRunners).where(and(eq(providerRunners.id, bootstrap.runnerInstanceId), eq(providerRunners.provisionerId, bootstrap.provisionerId))).limit(1);
108
114
  const [session] = await tx.insert(runnerControlSessions).values({
109
115
  runnerInstanceId: bootstrap.runnerInstanceId,
110
116
  provisionerId: bootstrap.provisionerId,
@@ -112,15 +118,28 @@ export async function exchangeRunnerBootstrapToken(params) {
112
118
  prefix: extractDisplayPrefix(controlSessionToken),
113
119
  expiresAt
114
120
  }).returning({
115
- id: runnerControlSessions.id
121
+ createdAt: runnerControlSessions.createdAt
116
122
  });
117
123
  if (!session) throw new Error('Runner control session insert returned no row');
118
124
  return {
125
+ runner,
126
+ session,
119
127
  runnerInstanceId: bootstrap.runnerInstanceId,
120
128
  controlSessionToken,
121
129
  expiresAt
122
130
  };
123
131
  });
132
+ if (result.runner) recordProviderRunnerCreatedToControlSession({
133
+ durationMilliseconds: result.session.createdAt.getTime() - result.runner.createdAt.getTime(),
134
+ provider: result.runner.provider,
135
+ launchKind: result.runner.launchKind,
136
+ runnerInstanceId: result.runner.runnerInstanceId
137
+ });
138
+ return {
139
+ runnerInstanceId: result.runnerInstanceId,
140
+ controlSessionToken: result.controlSessionToken,
141
+ expiresAt: result.expiresAt
142
+ };
124
143
  }
125
144
  export async function resolveRunnerControlSession(rawToken) {
126
145
  const [session] = await db().select({
@@ -131,7 +150,7 @@ export async function resolveRunnerControlSession(rawToken) {
131
150
  return session;
132
151
  }
133
152
  export async function enrollRunnerControlSession(params) {
134
- return await db().transaction(async (tx)=>{
153
+ const result = await db().transaction(async (tx)=>{
135
154
  const [current] = await tx.select({
136
155
  intendedReservationId: providerRunners.intendedReservationId,
137
156
  provisionerScope: provisionerTokens.scope
@@ -170,24 +189,41 @@ export async function enrollRunnerControlSession(params) {
170
189
  if (!updated) throw new RunnerControlSessionInvalidError();
171
190
  await updateRunnerControlSessionLastSeen(tx, params.runnerInstanceId, params.provisionerId);
172
191
  const intendedReservationId = updated.intendedReservationId;
173
- if (!intendedReservationId) return null;
192
+ if (!intendedReservationId) return {
193
+ activationToken: null,
194
+ controlSessionToAssignment: [],
195
+ assignmentRejectedReason: null,
196
+ promotionFailureReason: null
197
+ };
174
198
  try {
175
- return await tx.transaction(async (promotionTx)=>{
176
- await assignRunnerInstancesTx(promotionTx, {
199
+ const promotion = await tx.transaction(async (promotionTx)=>{
200
+ const assignment = await assignRunnerInstancesTx(promotionTx, {
177
201
  provisionerId: params.provisionerId,
178
202
  reservationId: intendedReservationId,
179
203
  runnerInstanceIds: [
180
204
  params.runnerInstanceId
181
- ]
205
+ ],
206
+ surface: 'enrollment'
182
207
  });
183
- return await issueRunnerActivationTokenTx(promotionTx, {
208
+ const activationToken = await issueRunnerActivationTokenTx(promotionTx, {
184
209
  runnerInstanceId: params.runnerInstanceId,
185
210
  provisionerId: params.provisionerId,
186
211
  ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,
187
212
  surface: 'enrollment'
188
213
  });
214
+ return {
215
+ activationToken,
216
+ controlSessionToAssignment: assignment.controlSessionToAssignment
217
+ };
189
218
  });
219
+ return {
220
+ activationToken: promotion.activationToken,
221
+ controlSessionToAssignment: promotion.controlSessionToAssignment,
222
+ assignmentRejectedReason: null,
223
+ promotionFailureReason: null
224
+ };
190
225
  } catch (error) {
226
+ const assignmentRejectionReason = getRunnerAssignmentRejectionReason(error);
191
227
  const expectedFailureReason = getRunnerReservationPromotionFailureReason(error);
192
228
  const details = {
193
229
  err: error,
@@ -196,14 +232,28 @@ export async function enrollRunnerControlSession(params) {
196
232
  reservationId: intendedReservationId
197
233
  };
198
234
  if (expectedFailureReason) {
199
- recordRunnerReservationPromotionFailure(expectedFailureReason);
200
235
  logger().debug(details, 'Runner reservation could not be promoted during enrollment');
201
236
  } else {
202
237
  logger().error(details, 'Unexpected failure promoting runner reservation during enrollment');
203
238
  }
204
- return null;
239
+ return {
240
+ activationToken: null,
241
+ controlSessionToAssignment: [],
242
+ assignmentRejectedReason: assignmentRejectionReason,
243
+ promotionFailureReason: expectedFailureReason
244
+ };
205
245
  }
206
246
  });
247
+ for (const observation of result.controlSessionToAssignment)recordProviderRunnerControlSessionToAssignment(observation);
248
+ // These counters intentionally overlap: assignment_rejected records the assignment-facing
249
+ // reason, while reservation_promotion_failure records the enrollment recovery outcome. They
250
+ // answer different questions and must not be summed.
251
+ if (result.assignmentRejectedReason) recordProviderRunnerAssignmentRejected({
252
+ reason: result.assignmentRejectedReason,
253
+ surface: 'enrollment'
254
+ });
255
+ if (result.promotionFailureReason) recordRunnerReservationPromotionFailure(result.promotionFailureReason);
256
+ return result.activationToken;
207
257
  }
208
258
  function getRunnerReservationPromotionFailureReason(error) {
209
259
  if (error instanceof ReservationExpiredError) return 'reservation-expired';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/core/runner-control-sessions.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport type {NodePgDatabase} from '@shipfox/node-drizzle';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken} from '@shipfox/node-tokens';\nimport {and, eq, gt, isNull, notInArray, or, sql} from 'drizzle-orm';\nimport {config} from '#config.js';\nimport {\n ReservationExpiredError,\n ReservationNotFoundError,\n RunnerInstanceAlreadyAssignedError,\n RunnerInstanceNotAssignableError,\n} from '#core/errors.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {db, type schema, type Tx} from '#db/db.js';\nimport {\n assignRunnerInstancesTx,\n validateRunnerReservationCapacityTx,\n} from '#db/runner-assignments.js';\nimport {terminalStates} from '#db/runner-states.js';\nimport {provisionerTokens} from '#db/schema/provisioner-tokens.js';\nimport {runnerBootstrapTokens, runnerControlSessions} from '#db/schema/runner-control-sessions.js';\nimport {providerRunners} from '#db/schema/runner-instances.js';\nimport {\n type RunnerReservationPromotionFailureReason,\n recordRunnerReservationCapacityFailure,\n recordRunnerReservationPromotionFailure,\n} from '#metrics/index.js';\nimport {issueRunnerActivationTokenTx} from './runner-activation.js';\n\nexport class RunnerBootstrapTokenInvalidError extends Error {\n constructor() {\n super('Runner bootstrap token is invalid, expired, or has already been used');\n this.name = 'RunnerBootstrapTokenInvalidError';\n }\n}\n\nexport class RunnerControlSessionInvalidError extends Error {\n constructor() {\n super('Runner control session is invalid, expired, or closed');\n this.name = 'RunnerControlSessionInvalidError';\n }\n}\n\nexport async function createRunnerInstancesWithBootstrapTokens(params: {\n provisionerId: string;\n providerKind?: string | null;\n runnerInstances: Array<{\n templateKey?: string | null;\n reservationId?: string | null;\n }>;\n ttlSeconds: number;\n}): Promise<{\n runnerInstances: Array<{\n runnerInstanceId: string;\n bootstrapToken: string;\n requestIndex: number;\n }>;\n reservationUnavailable: boolean;\n}> {\n const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);\n return await db().transaction(async (tx) => {\n const reservationValidation = await validateRunnerReservationCapacityTx(tx, {\n provisionerId: params.provisionerId,\n requests: params.runnerInstances.reduce(\n (requests, runner) => {\n if (!runner.reservationId) return requests;\n const request = requests.find(\n (candidate) => candidate.reservationId === runner.reservationId,\n );\n if (request) request.count += 1;\n else requests.push({reservationId: runner.reservationId, count: 1});\n return requests;\n },\n [] as Array<{reservationId: string; count: number}>,\n ),\n });\n for (const {reason, count} of reservationValidation.unavailableByReservation.values())\n recordRunnerReservationCapacityFailure(reason, count);\n const remainingAcceptedByReservation = new Map(reservationValidation.acceptedByReservation);\n const runnerInstances = params.runnerInstances.flatMap((runner, requestIndex) => {\n if (!runner.reservationId) return [{...runner, requestIndex}];\n const remaining = remainingAcceptedByReservation.get(runner.reservationId) ?? 0;\n if (remaining === 0) return [];\n remainingAcceptedByReservation.set(runner.reservationId, remaining - 1);\n return [{...runner, requestIndex}];\n });\n\n if (runnerInstances.length === 0)\n return {\n runnerInstances: [],\n reservationUnavailable: reservationValidation.unavailableByReservation.size > 0,\n };\n\n const instances = await tx\n .insert(providerRunners)\n .values(\n runnerInstances.map((runner) => ({\n provisionerId: params.provisionerId,\n providerKind: params.providerKind ?? null,\n templateKey: runner.templateKey ?? null,\n intendedReservationId: runner.reservationId ?? null,\n launchKind: runner.reservationId ? ('demand' as const) : ('warm' as const),\n state: 'starting' as const,\n labels: [],\n reportedAt: new Date(),\n })),\n )\n .returning({id: providerRunners.id});\n const results = instances.map((instance, index) => {\n const runner = runnerInstances[index];\n if (!runner) throw new Error('Runner instance insert returned an unexpected row count');\n return {\n runnerInstanceId: instance.id,\n bootstrapToken: generateOpaqueToken('runnerBootstrapToken'),\n requestIndex: runner.requestIndex,\n };\n });\n await tx.insert(runnerBootstrapTokens).values(\n results.map((result) => ({\n runnerInstanceId: result.runnerInstanceId,\n provisionerId: params.provisionerId,\n hashedToken: hashOpaqueToken(result.bootstrapToken),\n prefix: extractDisplayPrefix(result.bootstrapToken),\n expiresAt,\n })),\n );\n return {\n runnerInstances: results,\n reservationUnavailable: reservationValidation.unavailableByReservation.size > 0,\n };\n });\n}\n\nexport async function exchangeRunnerBootstrapToken(params: {\n rawToken: string;\n ttlSeconds: number;\n}): Promise<{runnerInstanceId: string; controlSessionToken: string; expiresAt: Date}> {\n const controlSessionToken = generateOpaqueToken('runnerControlSession');\n const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);\n return await db().transaction(async (tx) => {\n const [bootstrap] = await tx\n .update(runnerBootstrapTokens)\n .set({consumedAt: sql`now()`})\n .where(\n and(\n eq(runnerBootstrapTokens.hashedToken, hashOpaqueToken(params.rawToken)),\n isNull(runnerBootstrapTokens.consumedAt),\n isNull(runnerBootstrapTokens.revokedAt),\n gt(runnerBootstrapTokens.expiresAt, sql`now()`),\n ),\n )\n .returning();\n if (!bootstrap) throw new RunnerBootstrapTokenInvalidError();\n const [session] = await tx\n .insert(runnerControlSessions)\n .values({\n runnerInstanceId: bootstrap.runnerInstanceId,\n provisionerId: bootstrap.provisionerId,\n hashedToken: hashOpaqueToken(controlSessionToken),\n prefix: extractDisplayPrefix(controlSessionToken),\n expiresAt,\n })\n .returning({id: runnerControlSessions.id});\n if (!session) throw new Error('Runner control session insert returned no row');\n return {runnerInstanceId: bootstrap.runnerInstanceId, controlSessionToken, expiresAt};\n });\n}\n\nexport async function resolveRunnerControlSession(rawToken: string) {\n const [session] = await db()\n .select({\n id: runnerControlSessions.id,\n runnerInstanceId: runnerControlSessions.runnerInstanceId,\n provisionerId: runnerControlSessions.provisionerId,\n })\n .from(runnerControlSessions)\n .leftJoin(provisionerTokens, eq(provisionerTokens.id, runnerControlSessions.provisionerId))\n .where(\n and(\n eq(runnerControlSessions.hashedToken, hashOpaqueToken(rawToken)),\n isNull(runnerControlSessions.closedAt),\n or(isNull(provisionerTokens.id), isNull(provisionerTokens.revokedAt)),\n gt(runnerControlSessions.expiresAt, sql`now()`),\n ),\n )\n .limit(1);\n return session;\n}\n\nexport async function enrollRunnerControlSession(params: {\n runnerInstanceId: string;\n provisionerId: string;\n labels: string[];\n capabilities?: RunnerToolCapabilitiesDto | null;\n providerKind: string;\n protocolVersion: string;\n}): Promise<string | null> {\n return await db().transaction(async (tx) => {\n const [current] = await tx\n .select({\n intendedReservationId: providerRunners.intendedReservationId,\n provisionerScope: provisionerTokens.scope,\n })\n .from(providerRunners)\n .innerJoin(provisionerTokens, eq(provisionerTokens.id, providerRunners.provisionerId))\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n ),\n );\n if (!current) throw new RunnerControlSessionInvalidError();\n if (current.intendedReservationId)\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`runners_assignment:${params.provisionerId}:${current.intendedReservationId}`}))`,\n );\n\n // Provider reports may populate reservationId before the assignment commits. assignedAt is\n // written by the assignment transaction, so keep the guard on that write boundary.\n const [metadataUpdated] = await tx\n .update(providerRunners)\n .set({\n labels: sanitizeRunnerLabels(params.labels, {\n scope: current.provisionerScope,\n source: 'runner control enrollment',\n }),\n providerKind: params.providerKind,\n protocolVersion: params.protocolVersion,\n capabilities: params.capabilities ?? null,\n })\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.assignedAt),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({id: providerRunners.id});\n if (!metadataUpdated)\n logger().debug(\n {runnerInstanceId: params.runnerInstanceId, provisionerId: params.provisionerId},\n 'Runner enrollment metadata update skipped for assigned or terminal runner',\n );\n\n const [updated] = await tx\n .update(providerRunners)\n .set({\n state: 'running',\n reportedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({\n id: providerRunners.id,\n intendedReservationId: providerRunners.intendedReservationId,\n });\n if (!updated) throw new RunnerControlSessionInvalidError();\n\n await updateRunnerControlSessionLastSeen(tx, params.runnerInstanceId, params.provisionerId);\n\n const intendedReservationId = updated.intendedReservationId;\n if (!intendedReservationId) return null;\n\n try {\n return await tx.transaction(async (promotionTx) => {\n await assignRunnerInstancesTx(promotionTx, {\n provisionerId: params.provisionerId,\n reservationId: intendedReservationId,\n runnerInstanceIds: [params.runnerInstanceId],\n });\n return await issueRunnerActivationTokenTx(promotionTx, {\n runnerInstanceId: params.runnerInstanceId,\n provisionerId: params.provisionerId,\n ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,\n surface: 'enrollment',\n });\n });\n } catch (error) {\n const expectedFailureReason = getRunnerReservationPromotionFailureReason(error);\n const details = {\n err: error,\n runnerInstanceId: params.runnerInstanceId,\n provisionerId: params.provisionerId,\n reservationId: intendedReservationId,\n };\n if (expectedFailureReason) {\n recordRunnerReservationPromotionFailure(expectedFailureReason);\n logger().debug(details, 'Runner reservation could not be promoted during enrollment');\n } else {\n logger().error(\n details,\n 'Unexpected failure promoting runner reservation during enrollment',\n );\n }\n return null;\n }\n });\n}\n\nfunction getRunnerReservationPromotionFailureReason(\n error: unknown,\n): RunnerReservationPromotionFailureReason | null {\n if (error instanceof ReservationExpiredError) return 'reservation-expired';\n if (error instanceof ReservationNotFoundError) return 'reservation-not-found';\n if (error instanceof RunnerInstanceAlreadyAssignedError) return 'already-assigned';\n if (error instanceof RunnerInstanceNotAssignableError) return 'not-assignable';\n return null;\n}\n\nexport async function attachRunnerControlProviderId(params: {\n runnerInstanceId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n const rows = 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 rows.length === 1;\n}\n\nexport async function touchRunnerControlSession(runnerInstanceId: string, provisionerId: string) {\n await updateRunnerControlSessionLastSeen(db(), runnerInstanceId, provisionerId);\n await db()\n .update(providerRunners)\n .set({reportedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.id, runnerInstanceId),\n eq(providerRunners.provisionerId, provisionerId),\n ),\n );\n}\n\nasync function updateRunnerControlSessionLastSeen(\n tx: Tx | NodePgDatabase<typeof schema>,\n runnerInstanceId: string,\n provisionerId: string,\n) {\n await tx\n .update(runnerControlSessions)\n .set({lastSeenAt: sql`now()`})\n .where(\n and(\n eq(runnerControlSessions.runnerInstanceId, runnerInstanceId),\n eq(runnerControlSessions.provisionerId, provisionerId),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n}\n"],"names":["logger","extractDisplayPrefix","generateOpaqueToken","hashOpaqueToken","and","eq","gt","isNull","notInArray","or","sql","config","ReservationExpiredError","ReservationNotFoundError","RunnerInstanceAlreadyAssignedError","RunnerInstanceNotAssignableError","sanitizeRunnerLabels","db","assignRunnerInstancesTx","validateRunnerReservationCapacityTx","terminalStates","provisionerTokens","runnerBootstrapTokens","runnerControlSessions","providerRunners","recordRunnerReservationCapacityFailure","recordRunnerReservationPromotionFailure","issueRunnerActivationTokenTx","RunnerBootstrapTokenInvalidError","Error","name","RunnerControlSessionInvalidError","createRunnerInstancesWithBootstrapTokens","params","expiresAt","Date","now","ttlSeconds","transaction","tx","reservationValidation","provisionerId","requests","runnerInstances","reduce","runner","reservationId","request","find","candidate","count","push","reason","unavailableByReservation","values","remainingAcceptedByReservation","Map","acceptedByReservation","flatMap","requestIndex","remaining","get","set","length","reservationUnavailable","size","instances","insert","map","providerKind","templateKey","intendedReservationId","launchKind","state","labels","reportedAt","returning","id","results","instance","index","runnerInstanceId","bootstrapToken","result","hashedToken","prefix","exchangeRunnerBootstrapToken","controlSessionToken","bootstrap","update","consumedAt","where","rawToken","revokedAt","session","resolveRunnerControlSession","select","from","leftJoin","closedAt","limit","enrollRunnerControlSession","current","provisionerScope","scope","innerJoin","execute","metadataUpdated","source","protocolVersion","capabilities","assignedAt","debug","updated","updatedAt","updateRunnerControlSessionLastSeen","promotionTx","runnerInstanceIds","RUNNER_ACTIVATION_TOKEN_TTL_SECONDS","surface","error","expectedFailureReason","getRunnerReservationPromotionFailureReason","details","err","attachRunnerControlProviderId","rows","providerRunnerId","touchRunnerControlSession","lastSeenAt"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/core/runner-control-sessions.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport type {NodePgDatabase} from '@shipfox/node-drizzle';\nimport {logger} from '@shipfox/node-opentelemetry';\nimport {extractDisplayPrefix, generateOpaqueToken, hashOpaqueToken} from '@shipfox/node-tokens';\nimport {and, eq, gt, isNull, notInArray, or, sql} from 'drizzle-orm';\nimport {config} from '#config.js';\nimport {\n getRunnerAssignmentRejectionReason,\n ReservationExpiredError,\n ReservationNotFoundError,\n RunnerInstanceAlreadyAssignedError,\n RunnerInstanceNotAssignableError,\n} from '#core/errors.js';\nimport {sanitizeRunnerLabels} from '#core/runner-labels.js';\nimport {db, type schema, type Tx} from '#db/db.js';\nimport {\n assignRunnerInstancesTx,\n validateRunnerReservationCapacityTx,\n} from '#db/runner-assignments.js';\nimport {terminalStates} from '#db/runner-states.js';\nimport {provisionerTokens} from '#db/schema/provisioner-tokens.js';\nimport {runnerBootstrapTokens, runnerControlSessions} from '#db/schema/runner-control-sessions.js';\nimport {providerRunners} from '#db/schema/runner-instances.js';\nimport {\n type RunnerReservationPromotionFailureReason,\n recordProviderRunnerAssignmentRejected,\n recordProviderRunnerControlSessionToAssignment,\n recordProviderRunnerCreatedToControlSession,\n recordRunnerReservationCapacityFailure,\n recordRunnerReservationPromotionFailure,\n} from '#metrics/index.js';\nimport {issueRunnerActivationTokenTx} from './runner-activation.js';\n\nexport class RunnerBootstrapTokenInvalidError extends Error {\n constructor() {\n super('Runner bootstrap token is invalid, expired, or has already been used');\n this.name = 'RunnerBootstrapTokenInvalidError';\n }\n}\n\nexport class RunnerControlSessionInvalidError extends Error {\n constructor() {\n super('Runner control session is invalid, expired, or closed');\n this.name = 'RunnerControlSessionInvalidError';\n }\n}\n\nexport async function createRunnerInstancesWithBootstrapTokens(params: {\n provisionerId: string;\n providerKind?: string | null;\n runnerInstances: Array<{\n templateKey?: string | null;\n reservationId?: string | null;\n }>;\n ttlSeconds: number;\n}): Promise<{\n runnerInstances: Array<{\n runnerInstanceId: string;\n bootstrapToken: string;\n requestIndex: number;\n }>;\n reservationUnavailable: boolean;\n}> {\n const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);\n return await db().transaction(async (tx) => {\n const reservationValidation = await validateRunnerReservationCapacityTx(tx, {\n provisionerId: params.provisionerId,\n requests: params.runnerInstances.reduce(\n (requests, runner) => {\n if (!runner.reservationId) return requests;\n const request = requests.find(\n (candidate) => candidate.reservationId === runner.reservationId,\n );\n if (request) request.count += 1;\n else requests.push({reservationId: runner.reservationId, count: 1});\n return requests;\n },\n [] as Array<{reservationId: string; count: number}>,\n ),\n });\n for (const {reason, count} of reservationValidation.unavailableByReservation.values())\n recordRunnerReservationCapacityFailure(reason, count);\n const remainingAcceptedByReservation = new Map(reservationValidation.acceptedByReservation);\n const runnerInstances = params.runnerInstances.flatMap((runner, requestIndex) => {\n if (!runner.reservationId) return [{...runner, requestIndex}];\n const remaining = remainingAcceptedByReservation.get(runner.reservationId) ?? 0;\n if (remaining === 0) return [];\n remainingAcceptedByReservation.set(runner.reservationId, remaining - 1);\n return [{...runner, requestIndex}];\n });\n\n if (runnerInstances.length === 0)\n return {\n runnerInstances: [],\n reservationUnavailable: reservationValidation.unavailableByReservation.size > 0,\n };\n\n const instances = await tx\n .insert(providerRunners)\n .values(\n runnerInstances.map((runner) => ({\n provisionerId: params.provisionerId,\n providerKind: params.providerKind ?? null,\n templateKey: runner.templateKey ?? null,\n intendedReservationId: runner.reservationId ?? null,\n launchKind: runner.reservationId ? ('demand' as const) : ('warm' as const),\n state: 'starting' as const,\n labels: [],\n reportedAt: new Date(),\n })),\n )\n .returning({id: providerRunners.id});\n const results = instances.map((instance, index) => {\n const runner = runnerInstances[index];\n if (!runner) throw new Error('Runner instance insert returned an unexpected row count');\n return {\n runnerInstanceId: instance.id,\n bootstrapToken: generateOpaqueToken('runnerBootstrapToken'),\n requestIndex: runner.requestIndex,\n };\n });\n await tx.insert(runnerBootstrapTokens).values(\n results.map((result) => ({\n runnerInstanceId: result.runnerInstanceId,\n provisionerId: params.provisionerId,\n hashedToken: hashOpaqueToken(result.bootstrapToken),\n prefix: extractDisplayPrefix(result.bootstrapToken),\n expiresAt,\n })),\n );\n return {\n runnerInstances: results,\n reservationUnavailable: reservationValidation.unavailableByReservation.size > 0,\n };\n });\n}\n\nexport async function exchangeRunnerBootstrapToken(params: {\n rawToken: string;\n ttlSeconds: number;\n}): Promise<{runnerInstanceId: string; controlSessionToken: string; expiresAt: Date}> {\n const controlSessionToken = generateOpaqueToken('runnerControlSession');\n const expiresAt = new Date(Date.now() + params.ttlSeconds * 1000);\n const result = await db().transaction(async (tx) => {\n const [bootstrap] = await tx\n .update(runnerBootstrapTokens)\n .set({consumedAt: sql`now()`})\n .where(\n and(\n eq(runnerBootstrapTokens.hashedToken, hashOpaqueToken(params.rawToken)),\n isNull(runnerBootstrapTokens.consumedAt),\n isNull(runnerBootstrapTokens.revokedAt),\n gt(runnerBootstrapTokens.expiresAt, sql`now()`),\n ),\n )\n .returning();\n if (!bootstrap) throw new RunnerBootstrapTokenInvalidError();\n const [runner] = await tx\n .select({\n runnerInstanceId: providerRunners.id,\n createdAt: providerRunners.createdAt,\n provider: providerRunners.providerKind,\n launchKind: providerRunners.launchKind,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.id, bootstrap.runnerInstanceId),\n eq(providerRunners.provisionerId, bootstrap.provisionerId),\n ),\n )\n .limit(1);\n const [session] = await tx\n .insert(runnerControlSessions)\n .values({\n runnerInstanceId: bootstrap.runnerInstanceId,\n provisionerId: bootstrap.provisionerId,\n hashedToken: hashOpaqueToken(controlSessionToken),\n prefix: extractDisplayPrefix(controlSessionToken),\n expiresAt,\n })\n .returning({createdAt: runnerControlSessions.createdAt});\n if (!session) throw new Error('Runner control session insert returned no row');\n return {\n runner,\n session,\n runnerInstanceId: bootstrap.runnerInstanceId,\n controlSessionToken,\n expiresAt,\n };\n });\n if (result.runner)\n recordProviderRunnerCreatedToControlSession({\n durationMilliseconds: result.session.createdAt.getTime() - result.runner.createdAt.getTime(),\n provider: result.runner.provider,\n launchKind: result.runner.launchKind,\n runnerInstanceId: result.runner.runnerInstanceId,\n });\n return {\n runnerInstanceId: result.runnerInstanceId,\n controlSessionToken: result.controlSessionToken,\n expiresAt: result.expiresAt,\n };\n}\n\nexport async function resolveRunnerControlSession(rawToken: string) {\n const [session] = await db()\n .select({\n id: runnerControlSessions.id,\n runnerInstanceId: runnerControlSessions.runnerInstanceId,\n provisionerId: runnerControlSessions.provisionerId,\n })\n .from(runnerControlSessions)\n .leftJoin(provisionerTokens, eq(provisionerTokens.id, runnerControlSessions.provisionerId))\n .where(\n and(\n eq(runnerControlSessions.hashedToken, hashOpaqueToken(rawToken)),\n isNull(runnerControlSessions.closedAt),\n or(isNull(provisionerTokens.id), isNull(provisionerTokens.revokedAt)),\n gt(runnerControlSessions.expiresAt, sql`now()`),\n ),\n )\n .limit(1);\n return session;\n}\n\nexport async function enrollRunnerControlSession(params: {\n runnerInstanceId: string;\n provisionerId: string;\n labels: string[];\n capabilities?: RunnerToolCapabilitiesDto | null;\n providerKind: string;\n protocolVersion: string;\n}): Promise<string | null> {\n const result = await db().transaction(async (tx) => {\n const [current] = await tx\n .select({\n intendedReservationId: providerRunners.intendedReservationId,\n provisionerScope: provisionerTokens.scope,\n })\n .from(providerRunners)\n .innerJoin(provisionerTokens, eq(provisionerTokens.id, providerRunners.provisionerId))\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n ),\n );\n if (!current) throw new RunnerControlSessionInvalidError();\n if (current.intendedReservationId)\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${`runners_assignment:${params.provisionerId}:${current.intendedReservationId}`}))`,\n );\n\n // Provider reports may populate reservationId before the assignment commits. assignedAt is\n // written by the assignment transaction, so keep the guard on that write boundary.\n const [metadataUpdated] = await tx\n .update(providerRunners)\n .set({\n labels: sanitizeRunnerLabels(params.labels, {\n scope: current.provisionerScope,\n source: 'runner control enrollment',\n }),\n providerKind: params.providerKind,\n protocolVersion: params.protocolVersion,\n capabilities: params.capabilities ?? null,\n })\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.assignedAt),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({id: providerRunners.id});\n if (!metadataUpdated)\n logger().debug(\n {runnerInstanceId: params.runnerInstanceId, provisionerId: params.provisionerId},\n 'Runner enrollment metadata update skipped for assigned or terminal runner',\n );\n\n const [updated] = await tx\n .update(providerRunners)\n .set({\n state: 'running',\n reportedAt: sql`now()`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n eq(providerRunners.id, params.runnerInstanceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({\n id: providerRunners.id,\n intendedReservationId: providerRunners.intendedReservationId,\n });\n if (!updated) throw new RunnerControlSessionInvalidError();\n\n await updateRunnerControlSessionLastSeen(tx, params.runnerInstanceId, params.provisionerId);\n\n const intendedReservationId = updated.intendedReservationId;\n if (!intendedReservationId)\n return {\n activationToken: null,\n controlSessionToAssignment: [],\n assignmentRejectedReason: null,\n promotionFailureReason: null,\n };\n\n try {\n const promotion = await tx.transaction(async (promotionTx) => {\n const assignment = await assignRunnerInstancesTx(promotionTx, {\n provisionerId: params.provisionerId,\n reservationId: intendedReservationId,\n runnerInstanceIds: [params.runnerInstanceId],\n surface: 'enrollment',\n });\n const activationToken = await issueRunnerActivationTokenTx(promotionTx, {\n runnerInstanceId: params.runnerInstanceId,\n provisionerId: params.provisionerId,\n ttlSeconds: config.RUNNER_ACTIVATION_TOKEN_TTL_SECONDS,\n surface: 'enrollment',\n });\n return {activationToken, controlSessionToAssignment: assignment.controlSessionToAssignment};\n });\n return {\n activationToken: promotion.activationToken,\n controlSessionToAssignment: promotion.controlSessionToAssignment,\n assignmentRejectedReason: null,\n promotionFailureReason: null,\n };\n } catch (error) {\n const assignmentRejectionReason = getRunnerAssignmentRejectionReason(error);\n const expectedFailureReason = getRunnerReservationPromotionFailureReason(error);\n const details = {\n err: error,\n runnerInstanceId: params.runnerInstanceId,\n provisionerId: params.provisionerId,\n reservationId: intendedReservationId,\n };\n if (expectedFailureReason) {\n logger().debug(details, 'Runner reservation could not be promoted during enrollment');\n } else {\n logger().error(\n details,\n 'Unexpected failure promoting runner reservation during enrollment',\n );\n }\n return {\n activationToken: null,\n controlSessionToAssignment: [],\n assignmentRejectedReason: assignmentRejectionReason,\n promotionFailureReason: expectedFailureReason,\n };\n }\n });\n for (const observation of result.controlSessionToAssignment)\n recordProviderRunnerControlSessionToAssignment(observation);\n // These counters intentionally overlap: assignment_rejected records the assignment-facing\n // reason, while reservation_promotion_failure records the enrollment recovery outcome. They\n // answer different questions and must not be summed.\n if (result.assignmentRejectedReason)\n recordProviderRunnerAssignmentRejected({\n reason: result.assignmentRejectedReason,\n surface: 'enrollment',\n });\n if (result.promotionFailureReason)\n recordRunnerReservationPromotionFailure(result.promotionFailureReason);\n return result.activationToken;\n}\n\nfunction getRunnerReservationPromotionFailureReason(\n error: unknown,\n): RunnerReservationPromotionFailureReason | null {\n if (error instanceof ReservationExpiredError) return 'reservation-expired';\n if (error instanceof ReservationNotFoundError) return 'reservation-not-found';\n if (error instanceof RunnerInstanceAlreadyAssignedError) return 'already-assigned';\n if (error instanceof RunnerInstanceNotAssignableError) return 'not-assignable';\n return null;\n}\n\nexport async function attachRunnerControlProviderId(params: {\n runnerInstanceId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n const rows = 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 rows.length === 1;\n}\n\nexport async function touchRunnerControlSession(runnerInstanceId: string, provisionerId: string) {\n await updateRunnerControlSessionLastSeen(db(), runnerInstanceId, provisionerId);\n await db()\n .update(providerRunners)\n .set({reportedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.id, runnerInstanceId),\n eq(providerRunners.provisionerId, provisionerId),\n ),\n );\n}\n\nasync function updateRunnerControlSessionLastSeen(\n tx: Tx | NodePgDatabase<typeof schema>,\n runnerInstanceId: string,\n provisionerId: string,\n) {\n await tx\n .update(runnerControlSessions)\n .set({lastSeenAt: sql`now()`})\n .where(\n and(\n eq(runnerControlSessions.runnerInstanceId, runnerInstanceId),\n eq(runnerControlSessions.provisionerId, provisionerId),\n isNull(runnerControlSessions.closedAt),\n ),\n );\n}\n"],"names":["logger","extractDisplayPrefix","generateOpaqueToken","hashOpaqueToken","and","eq","gt","isNull","notInArray","or","sql","config","getRunnerAssignmentRejectionReason","ReservationExpiredError","ReservationNotFoundError","RunnerInstanceAlreadyAssignedError","RunnerInstanceNotAssignableError","sanitizeRunnerLabels","db","assignRunnerInstancesTx","validateRunnerReservationCapacityTx","terminalStates","provisionerTokens","runnerBootstrapTokens","runnerControlSessions","providerRunners","recordProviderRunnerAssignmentRejected","recordProviderRunnerControlSessionToAssignment","recordProviderRunnerCreatedToControlSession","recordRunnerReservationCapacityFailure","recordRunnerReservationPromotionFailure","issueRunnerActivationTokenTx","RunnerBootstrapTokenInvalidError","Error","name","RunnerControlSessionInvalidError","createRunnerInstancesWithBootstrapTokens","params","expiresAt","Date","now","ttlSeconds","transaction","tx","reservationValidation","provisionerId","requests","runnerInstances","reduce","runner","reservationId","request","find","candidate","count","push","reason","unavailableByReservation","values","remainingAcceptedByReservation","Map","acceptedByReservation","flatMap","requestIndex","remaining","get","set","length","reservationUnavailable","size","instances","insert","map","providerKind","templateKey","intendedReservationId","launchKind","state","labels","reportedAt","returning","id","results","instance","index","runnerInstanceId","bootstrapToken","result","hashedToken","prefix","exchangeRunnerBootstrapToken","controlSessionToken","bootstrap","update","consumedAt","where","rawToken","revokedAt","select","createdAt","provider","from","limit","session","durationMilliseconds","getTime","resolveRunnerControlSession","leftJoin","closedAt","enrollRunnerControlSession","current","provisionerScope","scope","innerJoin","execute","metadataUpdated","source","protocolVersion","capabilities","assignedAt","debug","updated","updatedAt","updateRunnerControlSessionLastSeen","activationToken","controlSessionToAssignment","assignmentRejectedReason","promotionFailureReason","promotion","promotionTx","assignment","runnerInstanceIds","surface","RUNNER_ACTIVATION_TOKEN_TTL_SECONDS","error","assignmentRejectionReason","expectedFailureReason","getRunnerReservationPromotionFailureReason","details","err","observation","attachRunnerControlProviderId","rows","providerRunnerId","touchRunnerControlSession","lastSeenAt"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"job-executions.d.ts","sourceRoot":"","sources":["../../src/db/job-executions.ts"],"names":[],"mappings":"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"}
@@ -4,7 +4,7 @@ import { writeOutboxEvent, writeOutboxEvents } from '@shipfox/node-outbox';
4
4
  import { canonicalizeLabels } from '@shipfox/runner-labels';
5
5
  import { and, arrayContained, asc, count, desc, eq, gt, inArray, isNotNull, isNull, lt, lte, or, sql } from 'drizzle-orm';
6
6
  import { EmptyRequiredLabelsError, RunnerSessionExhaustedError, RunningJobExecutionNotFoundError } from '#core/errors.js';
7
- import { jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount } from '#metrics/instance.js';
7
+ import { jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, recordJobExecutionQueueTime, recordProviderRunnerActivationToFirstClaim } from '#metrics/instance.js';
8
8
  import { db } from './db.js';
9
9
  import { runnersOutbox } from './schema/outbox.js';
10
10
  import { pendingJobExecutions } from './schema/pending-job-executions.js';
@@ -94,7 +94,9 @@ export async function claimPendingJobExecution(params) {
94
94
  throttleSeconds: params.runnerSessionLivenessThrottleSeconds
95
95
  });
96
96
  if (params.sessionLabels.length === 0) return null;
97
- return await db().transaction(async (tx)=>{
97
+ let activationToFirstClaimObservation = null;
98
+ let queueTimeObservation = null;
99
+ const result = await db().transaction(async (tx)=>{
98
100
  let provisionerId = null;
99
101
  let providerRunnerId = null;
100
102
  let runnerInstanceId = null;
@@ -155,12 +157,38 @@ export async function claimPendingJobExecution(params) {
155
157
  });
156
158
  const claimed = inserted[0];
157
159
  if (!claimed) return null;
160
+ queueTimeObservation = {
161
+ durationMilliseconds: claimed.claimedAt.getTime() - row.createdAt.getTime(),
162
+ provider: null,
163
+ launchKind: params.maxClaims === null ? 'manual' : 'unknown'
164
+ };
158
165
  const runnerInstanceCondition = runnerInstanceId ? eq(providerRunners.id, runnerInstanceId) : provisionerId && providerRunnerId ? and(eq(providerRunners.provisionerId, provisionerId), eq(providerRunners.providerRunnerId, providerRunnerId)) : null;
159
166
  if (runnerInstanceCondition) {
160
- await tx.update(providerRunners).set({
167
+ const [claimedRunner] = await tx.update(providerRunners).set({
161
168
  firstClaimedAt: sql`coalesce(${providerRunners.firstClaimedAt}, ${claimed.claimedAt})`,
162
169
  updatedAt: sql`now()`
163
- }).where(runnerInstanceCondition);
170
+ }).where(runnerInstanceCondition).returning({
171
+ firstClaimedAt: providerRunners.firstClaimedAt,
172
+ isFirstClaim: sql`${providerRunners.firstClaimedAt} = ${claimed.claimedAt}`,
173
+ provider: providerRunners.providerKind,
174
+ launchKind: providerRunners.launchKind,
175
+ runnerInstanceId: providerRunners.id,
176
+ sessionCreatedAtEpochMs: sql`(
177
+ select extract(epoch from ${runnerSessions.createdAt})::double precision * 1000
178
+ from ${runnerSessions}
179
+ where ${runnerSessions.id} = ${params.runnerSessionId}
180
+ )`
181
+ });
182
+ if (claimedRunner && queueTimeObservation) {
183
+ queueTimeObservation.provider = claimedRunner.provider;
184
+ queueTimeObservation.launchKind = claimedRunner.launchKind;
185
+ }
186
+ if (claimedRunner?.isFirstClaim && claimedRunner.firstClaimedAt !== null && claimedRunner.sessionCreatedAtEpochMs !== null && claimedRunner.sessionCreatedAtEpochMs !== undefined) activationToFirstClaimObservation = {
187
+ durationMilliseconds: claimedRunner.firstClaimedAt.getTime() - claimedRunner.sessionCreatedAtEpochMs,
188
+ provider: claimedRunner.provider,
189
+ launchKind: claimedRunner.launchKind,
190
+ runnerInstanceId: claimedRunner.runnerInstanceId
191
+ };
164
192
  }
165
193
  if (params.maxClaims !== null) {
166
194
  await tx.update(runnerSessions).set({
@@ -189,6 +217,9 @@ export async function claimPendingJobExecution(params) {
189
217
  projectId: row.projectId
190
218
  };
191
219
  });
220
+ if (queueTimeObservation) recordJobExecutionQueueTime(queueTimeObservation);
221
+ if (activationToFirstClaimObservation) recordProviderRunnerActivationToFirstClaim(activationToFirstClaimObservation);
222
+ return result;
192
223
  }
193
224
  async function touchRunnerSessionLiveness(params) {
194
225
  await db().update(runnerSessions).set({