@shipfox/api-runners 12.3.0 → 12.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/.turbo/turbo-build.log +4 -4
  2. package/CHANGELOG.md +36 -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/errors.d.ts +5 -1
  18. package/dist/core/errors.d.ts.map +1 -1
  19. package/dist/core/errors.js +9 -2
  20. package/dist/core/errors.js.map +1 -1
  21. package/dist/core/runner-activation.d.ts +4 -1
  22. package/dist/core/runner-activation.d.ts.map +1 -1
  23. package/dist/core/runner-activation.js +32 -3
  24. package/dist/core/runner-activation.js.map +1 -1
  25. package/dist/core/runner-control-sessions.d.ts +8 -4
  26. package/dist/core/runner-control-sessions.d.ts.map +1 -1
  27. package/dist/core/runner-control-sessions.js +116 -20
  28. package/dist/core/runner-control-sessions.js.map +1 -1
  29. package/dist/core/runner-instances.d.ts +1 -0
  30. package/dist/core/runner-instances.d.ts.map +1 -1
  31. package/dist/core/runner-instances.js +1 -0
  32. package/dist/core/runner-instances.js.map +1 -1
  33. package/dist/db/db.d.ts +68 -0
  34. package/dist/db/db.d.ts.map +1 -1
  35. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
  36. package/dist/db/ephemeral-registration-tokens.js +1 -1
  37. package/dist/db/ephemeral-registration-tokens.js.map +1 -1
  38. package/dist/db/job-executions.d.ts.map +1 -1
  39. package/dist/db/job-executions.js +35 -4
  40. package/dist/db/job-executions.js.map +1 -1
  41. package/dist/db/reservation-locks.d.ts +6 -0
  42. package/dist/db/reservation-locks.d.ts.map +1 -0
  43. package/dist/db/reservation-locks.js +15 -0
  44. package/dist/db/reservation-locks.js.map +1 -0
  45. package/dist/db/reservations.d.ts +17 -3
  46. package/dist/db/reservations.d.ts.map +1 -1
  47. package/dist/db/reservations.js +246 -51
  48. package/dist/db/reservations.js.map +1 -1
  49. package/dist/db/runner-assignments.d.ts +25 -1
  50. package/dist/db/runner-assignments.d.ts.map +1 -1
  51. package/dist/db/runner-assignments.js +160 -18
  52. package/dist/db/runner-assignments.js.map +1 -1
  53. package/dist/db/runner-instances.d.ts +11 -2
  54. package/dist/db/runner-instances.d.ts.map +1 -1
  55. package/dist/db/runner-instances.js +167 -24
  56. package/dist/db/runner-instances.js.map +1 -1
  57. package/dist/db/runner-sessions.d.ts.map +1 -1
  58. package/dist/db/runner-sessions.js +14 -1
  59. package/dist/db/runner-sessions.js.map +1 -1
  60. package/dist/db/runner-states.d.ts +2 -0
  61. package/dist/db/runner-states.d.ts.map +1 -0
  62. package/dist/db/runner-states.js +7 -0
  63. package/dist/db/runner-states.js.map +1 -0
  64. package/dist/db/schema/reservations.d.ts +18 -0
  65. package/dist/db/schema/reservations.d.ts.map +1 -1
  66. package/dist/db/schema/reservations.js +7 -1
  67. package/dist/db/schema/reservations.js.map +1 -1
  68. package/dist/db/schema/runner-instances.d.ts +18 -0
  69. package/dist/db/schema/runner-instances.d.ts.map +1 -1
  70. package/dist/db/schema/runner-instances.js +8 -0
  71. package/dist/db/schema/runner-instances.js.map +1 -1
  72. package/dist/metrics/index.d.ts +2 -2
  73. package/dist/metrics/index.d.ts.map +1 -1
  74. package/dist/metrics/index.js +1 -1
  75. package/dist/metrics/index.js.map +1 -1
  76. package/dist/metrics/instance.d.ts +72 -2
  77. package/dist/metrics/instance.d.ts.map +1 -1
  78. package/dist/metrics/instance.js +161 -1
  79. package/dist/metrics/instance.js.map +1 -1
  80. package/dist/metrics/service.d.ts.map +1 -1
  81. package/dist/metrics/service.js +25 -4
  82. package/dist/metrics/service.js.map +1 -1
  83. package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
  84. package/dist/presentation/dto/poll-demand.js +3 -0
  85. package/dist/presentation/dto/poll-demand.js.map +1 -1
  86. package/dist/presentation/dto/runner-instances.d.ts +4 -1
  87. package/dist/presentation/dto/runner-instances.d.ts.map +1 -1
  88. package/dist/presentation/dto/runner-instances.js +4 -1
  89. package/dist/presentation/dto/runner-instances.js.map +1 -1
  90. package/dist/presentation/routes/assign-runner-instances.d.ts.map +1 -1
  91. package/dist/presentation/routes/assign-runner-instances.js +10 -4
  92. package/dist/presentation/routes/assign-runner-instances.js.map +1 -1
  93. package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
  94. package/dist/presentation/routes/poll-demand.js +1 -0
  95. package/dist/presentation/routes/poll-demand.js.map +1 -1
  96. package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -1
  97. package/dist/presentation/routes/reconcile-runner-instances.js +4 -2
  98. package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -1
  99. package/dist/presentation/routes/runner-enrollment.d.ts +4 -1
  100. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -1
  101. package/dist/presentation/routes/runner-enrollment.js +11 -6
  102. package/dist/presentation/routes/runner-enrollment.js.map +1 -1
  103. package/dist/tsconfig.test.tsbuildinfo +1 -1
  104. package/drizzle/0005_previous_lenny_balinger.sql +5 -0
  105. package/drizzle/meta/0005_snapshot.json +2220 -0
  106. package/drizzle/meta/_journal.json +7 -0
  107. package/package.json +6 -6
  108. package/src/config.test.ts +22 -0
  109. package/src/config.ts +15 -2
  110. package/src/core/demand.test.ts +192 -3
  111. package/src/core/demand.ts +44 -4
  112. package/src/core/entities/reservation.ts +1 -0
  113. package/src/core/entities/runner-instance.ts +4 -0
  114. package/src/core/errors.ts +30 -1
  115. package/src/core/runner-activation.ts +48 -2
  116. package/src/core/runner-control-sessions.test.ts +135 -3
  117. package/src/core/runner-control-sessions.ts +141 -19
  118. package/src/core/runner-instances.test.ts +19 -0
  119. package/src/core/runner-instances.ts +2 -0
  120. package/src/core/runner-sessions.test.ts +121 -1
  121. package/src/db/ephemeral-registration-tokens.test.ts +20 -1
  122. package/src/db/ephemeral-registration-tokens.ts +1 -0
  123. package/src/db/job-executions.test.ts +98 -12
  124. package/src/db/job-executions.ts +52 -4
  125. package/src/db/reservation-locks.ts +22 -0
  126. package/src/db/reservations.test.ts +733 -22
  127. package/src/db/reservations.ts +408 -144
  128. package/src/db/runner-assignments.test.ts +105 -1
  129. package/src/db/runner-assignments.ts +245 -25
  130. package/src/db/runner-instances.test.ts +357 -2
  131. package/src/db/runner-instances.ts +289 -55
  132. package/src/db/runner-sessions.ts +19 -1
  133. package/src/db/runner-states.ts +7 -0
  134. package/src/db/schema/reservations.ts +5 -1
  135. package/src/db/schema/runner-instances.ts +9 -0
  136. package/src/metrics/index.ts +24 -1
  137. package/src/metrics/instance.test.ts +118 -0
  138. package/src/metrics/instance.ts +247 -3
  139. package/src/metrics/service.test.ts +46 -1
  140. package/src/metrics/service.ts +55 -8
  141. package/src/presentation/dto/poll-demand.ts +3 -0
  142. package/src/presentation/dto/runner-instances.ts +8 -1
  143. package/src/presentation/routes/assign-runner-instances.ts +14 -2
  144. package/src/presentation/routes/late-runner-enrollment.test.ts +219 -2
  145. package/src/presentation/routes/poll-demand.test.ts +56 -0
  146. package/src/presentation/routes/poll-demand.ts +1 -0
  147. package/src/presentation/routes/reconcile-runner-instances.test.ts +34 -2
  148. package/src/presentation/routes/reconcile-runner-instances.ts +7 -1
  149. package/src/presentation/routes/runner-enrollment.test.ts +316 -3
  150. package/src/presentation/routes/runner-enrollment.ts +8 -5
  151. package/test/factories/reservation.ts +2 -0
  152. package/test/factories/runner-instance.ts +6 -0
  153. package/tsconfig.build.tsbuildinfo +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../../src/db/schema/runner-instances.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,mCAAmC,CAAC;AAGtE,eAAO,MAAM,uBAAuB,8GAOlC,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAwD3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AACnE,MAAM,MAAM,sBAAsB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEzE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,cAAc,CAyBtE"}
1
+ {"version":3,"file":"runner-instances.d.ts","sourceRoot":"","sources":["../../../src/db/schema/runner-instances.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,cAAc,EAAC,MAAM,mCAAmC,CAAC;AAGtE,eAAO,MAAM,uBAAuB,8GAOlC,CAAC;AAEH,eAAO,MAAM,4BAA4B,oEAIvC,CAAC;AAEH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyD3B,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AACnE,MAAM,MAAM,sBAAsB,GAAG,OAAO,eAAe,CAAC,YAAY,CAAC;AAEzE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,gBAAgB,GAAG,cAAc,CA2BtE"}
@@ -10,6 +10,11 @@ export const providerRunnerStateEnum = pgEnum('runners_provider_runner_state', [
10
10
  'failed',
11
11
  'terminated'
12
12
  ]);
13
+ export const providerRunnerLaunchKindEnum = pgEnum('runners_provider_runner_launch_kind', [
14
+ 'demand',
15
+ 'warm',
16
+ 'manual'
17
+ ]);
13
18
  export const providerRunners = pgTable('runner_instances', {
14
19
  id: uuidv7PrimaryKey(),
15
20
  // Kept during the protocol migration for legacy workspace capacity. New capacity is owned
@@ -19,6 +24,7 @@ export const providerRunners = pgTable('runner_instances', {
19
24
  providerRunnerId: text('provider_runner_id'),
20
25
  intendedReservationId: uuid('intended_reservation_id'),
21
26
  reservationId: uuid('reservation_id'),
27
+ launchKind: providerRunnerLaunchKindEnum('launch_kind').notNull().default('manual'),
22
28
  assignedAt: timestamp('assigned_at', {
23
29
  withTimezone: true
24
30
  }),
@@ -76,7 +82,9 @@ export function toRunnerInstance(row) {
76
82
  workspaceId: row.workspaceId,
77
83
  provisionerId: row.provisionerId,
78
84
  providerRunnerId: row.providerRunnerId,
85
+ intendedReservationId: row.intendedReservationId,
79
86
  reservationId: row.reservationId,
87
+ launchKind: row.launchKind,
80
88
  assignedAt: row.assignedAt,
81
89
  templateKey: row.templateKey,
82
90
  labels: row.labels,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/db/schema/runner-instances.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {uuidv7PrimaryKey} from '@shipfox/node-drizzle';\nimport {sql} from 'drizzle-orm';\nimport {index, jsonb, pgEnum, text, timestamp, uniqueIndex, uuid} from 'drizzle-orm/pg-core';\nimport type {RunnerInstance} from '#core/entities/runner-instance.js';\nimport {pgTable} from './common.js';\n\nexport const providerRunnerStateEnum = pgEnum('runners_provider_runner_state', [\n 'starting',\n 'running',\n 'stopping',\n 'stopped',\n 'failed',\n 'terminated',\n]);\n\nexport const providerRunners = pgTable(\n 'runner_instances',\n {\n id: uuidv7PrimaryKey(),\n // Kept during the protocol migration for legacy workspace capacity. New capacity is owned\n // only by its provisioner and has no workspace assignment.\n workspaceId: uuid('workspace_id'),\n provisionerId: uuid('provisioner_id').notNull(),\n providerRunnerId: text('provider_runner_id'),\n intendedReservationId: uuid('intended_reservation_id'),\n reservationId: uuid('reservation_id'),\n assignedAt: timestamp('assigned_at', {withTimezone: true}),\n templateKey: text('template_key'),\n labels: text('labels').array().notNull().default([]),\n state: providerRunnerStateEnum('state').notNull(),\n reason: text('reason'),\n runnerSessionId: uuid('runner_session_id'),\n firstClaimedAt: timestamp('first_claimed_at', {withTimezone: true}),\n providerKind: text('provider_kind'),\n protocolVersion: text('protocol_version'),\n capabilities: jsonb('capabilities').$type<RunnerToolCapabilitiesDto | null>(),\n reportedAt: timestamp('reported_at', {withTimezone: true}).notNull(),\n startedAt: timestamp('started_at', {withTimezone: true}),\n stoppingAt: timestamp('stopping_at', {withTimezone: true}),\n stoppedAt: timestamp('stopped_at', {withTimezone: true}),\n failedAt: timestamp('failed_at', {withTimezone: true}),\n terminatedAt: timestamp('terminated_at', {withTimezone: true}),\n reservationReleasedAt: timestamp('reservation_released_at', {withTimezone: true}),\n createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', {withTimezone: true}).notNull().defaultNow(),\n },\n (table) => [\n uniqueIndex('runners_runner_instances_provisioner_runner_unique')\n .on(table.provisionerId, table.providerRunnerId)\n .where(sql`${table.providerRunnerId} is not null`),\n index('runners_runner_instances_workspace_state_updated_idx').on(table.state, table.updatedAt),\n index('runners_runner_instances_stale_reaper_idx').on(\n table.state,\n table.updatedAt,\n table.reportedAt,\n ),\n index('runners_runner_instances_provisioner_intended_reservation_idx')\n .on(table.provisionerId, table.intendedReservationId)\n .where(\n sql`${table.intendedReservationId} is not null and ${table.reservationReleasedAt} is null`,\n ),\n index('runners_runner_instances_intended_reservation_idx')\n .on(table.intendedReservationId)\n .where(sql`${table.intendedReservationId} is not null`),\n index('runners_runner_instances_provisioner_reservation_idx')\n .on(table.provisionerId, table.reservationId)\n .where(sql`${table.reservationId} is not null`),\n index('runners_runner_instances_active_template_counts_idx')\n .on(table.provisionerId, table.state, table.templateKey)\n .where(sql`\"state\" in ('starting', 'running') and \"template_key\" is not null`),\n ],\n);\n\nexport type RunnerInstanceDb = typeof providerRunners.$inferSelect;\nexport type RunnerInstanceInsertDb = typeof providerRunners.$inferInsert;\n\nexport function toRunnerInstance(row: RunnerInstanceDb): RunnerInstance {\n if (!row.providerRunnerId) throw new Error('Runner instance has no provider runner identity');\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n provisionerId: row.provisionerId,\n providerRunnerId: row.providerRunnerId,\n reservationId: row.reservationId,\n assignedAt: row.assignedAt,\n templateKey: row.templateKey,\n labels: row.labels,\n state: row.state,\n reason: row.reason,\n runnerSessionId: row.runnerSessionId,\n providerKind: row.providerKind,\n reportedAt: row.reportedAt,\n startedAt: row.startedAt,\n stoppingAt: row.stoppingAt,\n stoppedAt: row.stoppedAt,\n failedAt: row.failedAt,\n terminatedAt: row.terminatedAt,\n reservationReleasedAt: row.reservationReleasedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n"],"names":["uuidv7PrimaryKey","sql","index","jsonb","pgEnum","text","timestamp","uniqueIndex","uuid","pgTable","providerRunnerStateEnum","providerRunners","id","workspaceId","provisionerId","notNull","providerRunnerId","intendedReservationId","reservationId","assignedAt","withTimezone","templateKey","labels","array","default","state","reason","runnerSessionId","firstClaimedAt","providerKind","protocolVersion","capabilities","$type","reportedAt","startedAt","stoppingAt","stoppedAt","failedAt","terminatedAt","reservationReleasedAt","createdAt","defaultNow","updatedAt","table","on","where","toRunnerInstance","row","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/db/schema/runner-instances.ts"],"sourcesContent":["import type {RunnerToolCapabilitiesDto} from '@shipfox/api-runners-dto';\nimport {uuidv7PrimaryKey} from '@shipfox/node-drizzle';\nimport {sql} from 'drizzle-orm';\nimport {index, jsonb, pgEnum, text, timestamp, uniqueIndex, uuid} from 'drizzle-orm/pg-core';\nimport type {RunnerInstance} from '#core/entities/runner-instance.js';\nimport {pgTable} from './common.js';\n\nexport const providerRunnerStateEnum = pgEnum('runners_provider_runner_state', [\n 'starting',\n 'running',\n 'stopping',\n 'stopped',\n 'failed',\n 'terminated',\n]);\n\nexport const providerRunnerLaunchKindEnum = pgEnum('runners_provider_runner_launch_kind', [\n 'demand',\n 'warm',\n 'manual',\n]);\n\nexport const providerRunners = pgTable(\n 'runner_instances',\n {\n id: uuidv7PrimaryKey(),\n // Kept during the protocol migration for legacy workspace capacity. New capacity is owned\n // only by its provisioner and has no workspace assignment.\n workspaceId: uuid('workspace_id'),\n provisionerId: uuid('provisioner_id').notNull(),\n providerRunnerId: text('provider_runner_id'),\n intendedReservationId: uuid('intended_reservation_id'),\n reservationId: uuid('reservation_id'),\n launchKind: providerRunnerLaunchKindEnum('launch_kind').notNull().default('manual'),\n assignedAt: timestamp('assigned_at', {withTimezone: true}),\n templateKey: text('template_key'),\n labels: text('labels').array().notNull().default([]),\n state: providerRunnerStateEnum('state').notNull(),\n reason: text('reason'),\n runnerSessionId: uuid('runner_session_id'),\n firstClaimedAt: timestamp('first_claimed_at', {withTimezone: true}),\n providerKind: text('provider_kind'),\n protocolVersion: text('protocol_version'),\n capabilities: jsonb('capabilities').$type<RunnerToolCapabilitiesDto | null>(),\n reportedAt: timestamp('reported_at', {withTimezone: true}).notNull(),\n startedAt: timestamp('started_at', {withTimezone: true}),\n stoppingAt: timestamp('stopping_at', {withTimezone: true}),\n stoppedAt: timestamp('stopped_at', {withTimezone: true}),\n failedAt: timestamp('failed_at', {withTimezone: true}),\n terminatedAt: timestamp('terminated_at', {withTimezone: true}),\n reservationReleasedAt: timestamp('reservation_released_at', {withTimezone: true}),\n createdAt: timestamp('created_at', {withTimezone: true}).notNull().defaultNow(),\n updatedAt: timestamp('updated_at', {withTimezone: true}).notNull().defaultNow(),\n },\n (table) => [\n uniqueIndex('runners_runner_instances_provisioner_runner_unique')\n .on(table.provisionerId, table.providerRunnerId)\n .where(sql`${table.providerRunnerId} is not null`),\n index('runners_runner_instances_workspace_state_updated_idx').on(table.state, table.updatedAt),\n index('runners_runner_instances_stale_reaper_idx').on(\n table.state,\n table.updatedAt,\n table.reportedAt,\n ),\n index('runners_runner_instances_provisioner_intended_reservation_idx')\n .on(table.provisionerId, table.intendedReservationId)\n .where(\n sql`${table.intendedReservationId} is not null and ${table.reservationReleasedAt} is null`,\n ),\n index('runners_runner_instances_intended_reservation_idx')\n .on(table.intendedReservationId)\n .where(sql`${table.intendedReservationId} is not null`),\n index('runners_runner_instances_provisioner_reservation_idx')\n .on(table.provisionerId, table.reservationId)\n .where(sql`${table.reservationId} is not null`),\n index('runners_runner_instances_active_template_counts_idx')\n .on(table.provisionerId, table.state, table.templateKey)\n .where(sql`\"state\" in ('starting', 'running') and \"template_key\" is not null`),\n ],\n);\n\nexport type RunnerInstanceDb = typeof providerRunners.$inferSelect;\nexport type RunnerInstanceInsertDb = typeof providerRunners.$inferInsert;\n\nexport function toRunnerInstance(row: RunnerInstanceDb): RunnerInstance {\n if (!row.providerRunnerId) throw new Error('Runner instance has no provider runner identity');\n return {\n id: row.id,\n workspaceId: row.workspaceId,\n provisionerId: row.provisionerId,\n providerRunnerId: row.providerRunnerId,\n intendedReservationId: row.intendedReservationId,\n reservationId: row.reservationId,\n launchKind: row.launchKind,\n assignedAt: row.assignedAt,\n templateKey: row.templateKey,\n labels: row.labels,\n state: row.state,\n reason: row.reason,\n runnerSessionId: row.runnerSessionId,\n providerKind: row.providerKind,\n reportedAt: row.reportedAt,\n startedAt: row.startedAt,\n stoppingAt: row.stoppingAt,\n stoppedAt: row.stoppedAt,\n failedAt: row.failedAt,\n terminatedAt: row.terminatedAt,\n reservationReleasedAt: row.reservationReleasedAt,\n createdAt: row.createdAt,\n updatedAt: row.updatedAt,\n };\n}\n"],"names":["uuidv7PrimaryKey","sql","index","jsonb","pgEnum","text","timestamp","uniqueIndex","uuid","pgTable","providerRunnerStateEnum","providerRunnerLaunchKindEnum","providerRunners","id","workspaceId","provisionerId","notNull","providerRunnerId","intendedReservationId","reservationId","launchKind","default","assignedAt","withTimezone","templateKey","labels","array","state","reason","runnerSessionId","firstClaimedAt","providerKind","protocolVersion","capabilities","$type","reportedAt","startedAt","stoppingAt","stoppedAt","failedAt","terminatedAt","reservationReleasedAt","createdAt","defaultNow","updatedAt","table","on","where","toRunnerInstance","row","Error"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type { RunnerReservationPromotionFailureReason } from './instance.js';
2
- export { jobExecutionClaimedCount, jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, providerRunnerAbsentTerminatedCount, providerRunnerCountDivergenceCount, providerRunnerReconcileCallCount, providerRunnerTerminateIntentHonoredCount, providerRunnerTerminateIntentIssuedCount, recordRunnerReservationPromotionFailure, recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure, } from './instance.js';
1
+ export type { RunnerActivationTokenNotIssuedReason, RunnerActivationTokenNotIssuedSurface, RunnerAssignmentSurface, RunnerLaunchKind, RunnerReservationCapacityFailureReason, RunnerReservationPromotionFailureReason, } from './instance.js';
2
+ export { jobExecutionClaimedCount, jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, jobExecutionQueueTimeDuration, providerRunnerAbsentTerminatedCount, providerRunnerActivationOutcomeCount, providerRunnerActivationToFirstClaimDuration, providerRunnerAssignmentRejectedCount, providerRunnerAssignmentToActivationDuration, providerRunnerControlSessionToAssignmentDuration, providerRunnerCountDivergenceCount, providerRunnerCreatedToControlSessionDuration, providerRunnerReconcileCallCount, providerRunnerTerminateIntentHonoredCount, providerRunnerTerminateIntentIssuedCount, recordJobExecutionQueueTime, recordProviderRunnerActivationOutcome, recordProviderRunnerActivationToFirstClaim, recordProviderRunnerAssignmentRejected, recordProviderRunnerAssignmentToActivation, recordProviderRunnerControlSessionToAssignment, recordProviderRunnerCreatedToControlSession, recordRunnerActivationTokenNotIssued, recordRunnerReservationCapacityFailure, recordRunnerReservationPromotionFailure, recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure, } from './instance.js';
3
3
  export { registerRunnersServiceMetrics } from './service.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAC,uCAAuC,EAAC,MAAM,eAAe,CAAC;AAC3E,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,6BAA6B,EAC7B,mCAAmC,EACnC,kCAAkC,EAClC,gCAAgC,EAChC,yCAAyC,EACzC,wCAAwC,EACxC,uCAAuC,EACvC,2BAA2B,EAC3B,kCAAkC,GACnC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,6BAA6B,EAAC,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,oCAAoC,EACpC,qCAAqC,EACrC,uBAAuB,EACvB,gBAAgB,EAChB,sCAAsC,EACtC,uCAAuC,GACxC,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,wBAAwB,EACxB,yBAAyB,EACzB,6BAA6B,EAC7B,6BAA6B,EAC7B,mCAAmC,EACnC,oCAAoC,EACpC,4CAA4C,EAC5C,qCAAqC,EACrC,4CAA4C,EAC5C,gDAAgD,EAChD,kCAAkC,EAClC,6CAA6C,EAC7C,gCAAgC,EAChC,yCAAyC,EACzC,wCAAwC,EACxC,2BAA2B,EAC3B,qCAAqC,EACrC,0CAA0C,EAC1C,sCAAsC,EACtC,0CAA0C,EAC1C,8CAA8C,EAC9C,2CAA2C,EAC3C,oCAAoC,EACpC,sCAAsC,EACtC,uCAAuC,EACvC,2BAA2B,EAC3B,kCAAkC,GACnC,MAAM,eAAe,CAAC;AACvB,OAAO,EAAC,6BAA6B,EAAC,MAAM,cAAc,CAAC"}
@@ -1,4 +1,4 @@
1
- export { jobExecutionClaimedCount, jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, providerRunnerAbsentTerminatedCount, providerRunnerCountDivergenceCount, providerRunnerReconcileCallCount, providerRunnerTerminateIntentHonoredCount, providerRunnerTerminateIntentIssuedCount, recordRunnerReservationPromotionFailure, recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure } from './instance.js';
1
+ export { jobExecutionClaimedCount, jobExecutionEnqueuedCount, jobExecutionLeaseExpiredCount, jobExecutionQueueTimeDuration, providerRunnerAbsentTerminatedCount, providerRunnerActivationOutcomeCount, providerRunnerActivationToFirstClaimDuration, providerRunnerAssignmentRejectedCount, providerRunnerAssignmentToActivationDuration, providerRunnerControlSessionToAssignmentDuration, providerRunnerCountDivergenceCount, providerRunnerCreatedToControlSessionDuration, providerRunnerReconcileCallCount, providerRunnerTerminateIntentHonoredCount, providerRunnerTerminateIntentIssuedCount, recordJobExecutionQueueTime, recordProviderRunnerActivationOutcome, recordProviderRunnerActivationToFirstClaim, recordProviderRunnerAssignmentRejected, recordProviderRunnerAssignmentToActivation, recordProviderRunnerControlSessionToAssignment, recordProviderRunnerCreatedToControlSession, recordRunnerActivationTokenNotIssued, recordRunnerReservationCapacityFailure, recordRunnerReservationPromotionFailure, recordRunnersRateLimitCheck, recordRunnersRateLimitPruneFailure } from './instance.js';
2
2
  export { registerRunnersServiceMetrics } from './service.js';
3
3
 
4
4
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/index.ts"],"sourcesContent":["export type {RunnerReservationPromotionFailureReason} from './instance.js';\nexport {\n jobExecutionClaimedCount,\n jobExecutionEnqueuedCount,\n jobExecutionLeaseExpiredCount,\n providerRunnerAbsentTerminatedCount,\n providerRunnerCountDivergenceCount,\n providerRunnerReconcileCallCount,\n providerRunnerTerminateIntentHonoredCount,\n providerRunnerTerminateIntentIssuedCount,\n recordRunnerReservationPromotionFailure,\n recordRunnersRateLimitCheck,\n recordRunnersRateLimitPruneFailure,\n} from './instance.js';\nexport {registerRunnersServiceMetrics} from './service.js';\n"],"names":["jobExecutionClaimedCount","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","providerRunnerAbsentTerminatedCount","providerRunnerCountDivergenceCount","providerRunnerReconcileCallCount","providerRunnerTerminateIntentHonoredCount","providerRunnerTerminateIntentIssuedCount","recordRunnerReservationPromotionFailure","recordRunnersRateLimitCheck","recordRunnersRateLimitPruneFailure","registerRunnersServiceMetrics"],"mappings":"AACA,SACEA,wBAAwB,EACxBC,yBAAyB,EACzBC,6BAA6B,EAC7BC,mCAAmC,EACnCC,kCAAkC,EAClCC,gCAAgC,EAChCC,yCAAyC,EACzCC,wCAAwC,EACxCC,uCAAuC,EACvCC,2BAA2B,EAC3BC,kCAAkC,QAC7B,gBAAgB;AACvB,SAAQC,6BAA6B,QAAO,eAAe"}
1
+ {"version":3,"sources":["../../src/metrics/index.ts"],"sourcesContent":["export type {\n RunnerActivationTokenNotIssuedReason,\n RunnerActivationTokenNotIssuedSurface,\n RunnerAssignmentSurface,\n RunnerLaunchKind,\n RunnerReservationCapacityFailureReason,\n RunnerReservationPromotionFailureReason,\n} from './instance.js';\nexport {\n jobExecutionClaimedCount,\n jobExecutionEnqueuedCount,\n jobExecutionLeaseExpiredCount,\n jobExecutionQueueTimeDuration,\n providerRunnerAbsentTerminatedCount,\n providerRunnerActivationOutcomeCount,\n providerRunnerActivationToFirstClaimDuration,\n providerRunnerAssignmentRejectedCount,\n providerRunnerAssignmentToActivationDuration,\n providerRunnerControlSessionToAssignmentDuration,\n providerRunnerCountDivergenceCount,\n providerRunnerCreatedToControlSessionDuration,\n providerRunnerReconcileCallCount,\n providerRunnerTerminateIntentHonoredCount,\n providerRunnerTerminateIntentIssuedCount,\n recordJobExecutionQueueTime,\n recordProviderRunnerActivationOutcome,\n recordProviderRunnerActivationToFirstClaim,\n recordProviderRunnerAssignmentRejected,\n recordProviderRunnerAssignmentToActivation,\n recordProviderRunnerControlSessionToAssignment,\n recordProviderRunnerCreatedToControlSession,\n recordRunnerActivationTokenNotIssued,\n recordRunnerReservationCapacityFailure,\n recordRunnerReservationPromotionFailure,\n recordRunnersRateLimitCheck,\n recordRunnersRateLimitPruneFailure,\n} from './instance.js';\nexport {registerRunnersServiceMetrics} from './service.js';\n"],"names":["jobExecutionClaimedCount","jobExecutionEnqueuedCount","jobExecutionLeaseExpiredCount","jobExecutionQueueTimeDuration","providerRunnerAbsentTerminatedCount","providerRunnerActivationOutcomeCount","providerRunnerActivationToFirstClaimDuration","providerRunnerAssignmentRejectedCount","providerRunnerAssignmentToActivationDuration","providerRunnerControlSessionToAssignmentDuration","providerRunnerCountDivergenceCount","providerRunnerCreatedToControlSessionDuration","providerRunnerReconcileCallCount","providerRunnerTerminateIntentHonoredCount","providerRunnerTerminateIntentIssuedCount","recordJobExecutionQueueTime","recordProviderRunnerActivationOutcome","recordProviderRunnerActivationToFirstClaim","recordProviderRunnerAssignmentRejected","recordProviderRunnerAssignmentToActivation","recordProviderRunnerControlSessionToAssignment","recordProviderRunnerCreatedToControlSession","recordRunnerActivationTokenNotIssued","recordRunnerReservationCapacityFailure","recordRunnerReservationPromotionFailure","recordRunnersRateLimitCheck","recordRunnersRateLimitPruneFailure","registerRunnersServiceMetrics"],"mappings":"AAQA,SACEA,wBAAwB,EACxBC,yBAAyB,EACzBC,6BAA6B,EAC7BC,6BAA6B,EAC7BC,mCAAmC,EACnCC,oCAAoC,EACpCC,4CAA4C,EAC5CC,qCAAqC,EACrCC,4CAA4C,EAC5CC,gDAAgD,EAChDC,kCAAkC,EAClCC,6CAA6C,EAC7CC,gCAAgC,EAChCC,yCAAyC,EACzCC,wCAAwC,EACxCC,2BAA2B,EAC3BC,qCAAqC,EACrCC,0CAA0C,EAC1CC,sCAAsC,EACtCC,0CAA0C,EAC1CC,8CAA8C,EAC9CC,2CAA2C,EAC3CC,oCAAoC,EACpCC,sCAAsC,EACtCC,uCAAuC,EACvCC,2BAA2B,EAC3BC,kCAAkC,QAC7B,gBAAgB;AACvB,SAAQC,6BAA6B,QAAO,eAAe"}
@@ -1,3 +1,41 @@
1
+ import type { RunnerAssignmentRejectionReason } from '#core/errors.js';
2
+ export type RunnerLaunchKind = 'demand' | 'warm' | 'manual';
3
+ export type RunnerAssignmentSurface = 'provisioner' | 'enrollment';
4
+ type ProviderRunnerLifecycleLabels = {
5
+ provider: string;
6
+ launch_kind: RunnerLaunchKind;
7
+ };
8
+ type ProviderRunnerAssignmentLifecycleLabels = ProviderRunnerLifecycleLabels & {
9
+ surface: RunnerAssignmentSurface;
10
+ };
11
+ type JobExecutionQueueTimeLabels = {
12
+ provider: string;
13
+ launch_kind: RunnerLaunchKind | 'unknown';
14
+ };
15
+ export interface JobExecutionQueueTimeObservation {
16
+ durationMilliseconds: number;
17
+ provider: string | null;
18
+ launchKind: RunnerLaunchKind | 'unknown';
19
+ }
20
+ export interface ProviderRunnerLifecycleObservation {
21
+ durationMilliseconds: number;
22
+ provider: string | null;
23
+ launchKind: RunnerLaunchKind;
24
+ runnerInstanceId?: string;
25
+ }
26
+ export interface ProviderRunnerAssignmentObservation extends ProviderRunnerLifecycleObservation {
27
+ surface: RunnerAssignmentSurface;
28
+ }
29
+ export declare const UNKNOWN_PROVIDER_KIND = "unknown";
30
+ export declare const providerRunnerCreatedToControlSessionDuration: import("@shipfox/node-opentelemetry").Histogram<ProviderRunnerLifecycleLabels>;
31
+ export declare const providerRunnerControlSessionToAssignmentDuration: import("@shipfox/node-opentelemetry").Histogram<ProviderRunnerAssignmentLifecycleLabels>;
32
+ export declare const providerRunnerAssignmentToActivationDuration: import("@shipfox/node-opentelemetry").Histogram<ProviderRunnerLifecycleLabels>;
33
+ export declare const providerRunnerActivationToFirstClaimDuration: import("@shipfox/node-opentelemetry").Histogram<ProviderRunnerLifecycleLabels>;
34
+ export declare const jobExecutionQueueTimeDuration: import("@shipfox/node-opentelemetry").Histogram<JobExecutionQueueTimeLabels>;
35
+ export declare const providerRunnerAssignmentRejectedCount: import("@shipfox/node-opentelemetry").Counter<{
36
+ reason: RunnerAssignmentRejectionReason;
37
+ surface: RunnerAssignmentSurface;
38
+ }>;
1
39
  export declare const jobExecutionEnqueuedCount: import("@shipfox/node-opentelemetry").Counter<Record<string, never>>;
2
40
  export declare const jobExecutionClaimedCount: import("@shipfox/node-opentelemetry").Counter<{
3
41
  outcome: 'claimed' | 'empty';
@@ -9,6 +47,12 @@ export declare const providerRunnerReportCount: import("@shipfox/node-openteleme
9
47
  export declare const runnerBootstrapExchangeCount: import("@shipfox/node-opentelemetry").Counter<{
10
48
  outcome: 'accepted' | 'rejected';
11
49
  }>;
50
+ export type RunnerActivationTokenNotIssuedReason = 'runner-not-found' | 'missing-workspace' | 'existing-session' | 'not-running';
51
+ export type RunnerActivationTokenNotIssuedSurface = 'enrollment' | 'poll';
52
+ export declare const runnerActivationTokenNotIssuedCount: import("@shipfox/node-opentelemetry").Counter<{
53
+ reason: RunnerActivationTokenNotIssuedReason;
54
+ surface: RunnerActivationTokenNotIssuedSurface;
55
+ }>;
12
56
  export declare const runnerControlHeartbeatCount: import("@shipfox/node-opentelemetry").Counter<Record<string, never>>;
13
57
  export declare const providerRunnerReapedCount: import("@shipfox/node-opentelemetry").Counter<Record<string, never>>;
14
58
  export declare const providerRunnerCountDivergenceCount: import("@shipfox/node-opentelemetry").Counter<{
@@ -20,24 +64,50 @@ export declare const providerRunnerReconcileCallCount: import("@shipfox/node-ope
20
64
  export declare const providerRunnerAbsentTerminatedCount: import("@shipfox/node-opentelemetry").Counter<Record<string, never>>;
21
65
  export declare const providerRunnerTerminateIntentIssuedCount: import("@shipfox/node-opentelemetry").Counter<{
22
66
  surface: 'poll-demand' | 'reconcile';
23
- reason: 'job-cancelled' | 'terminal-state';
67
+ reason: 'activation-timeout' | 'job-cancelled' | 'terminal-state';
24
68
  }>;
25
69
  export declare const providerRunnerTerminateIntentHonoredCount: import("@shipfox/node-opentelemetry").Counter<{
26
- reason: 'job-cancelled';
70
+ reason: 'activation-timeout' | 'job-cancelled';
71
+ }>;
72
+ export declare const providerRunnerActivationOutcomeCount: import("@shipfox/node-opentelemetry").Counter<{
73
+ outcome: 'reaped' | 'rebound';
27
74
  }>;
28
75
  export declare const reservationReleasedCount: import("@shipfox/node-opentelemetry").Counter<Record<string, never>>;
29
76
  export type RunnerReservationPromotionFailureReason = 'reservation-expired' | 'reservation-not-found' | 'already-assigned' | 'not-assignable';
30
77
  export declare const runnerReservationPromotionFailureCount: import("@shipfox/node-opentelemetry").Counter<{
31
78
  reason: RunnerReservationPromotionFailureReason;
32
79
  }>;
80
+ export type RunnerReservationCapacityFailureReason = 'reservation-not-found' | 'reservation-kind-mismatch' | 'reservation-expired' | 'capacity-exhausted';
81
+ export declare const runnerReservationCapacityFailureCount: import("@shipfox/node-opentelemetry").Counter<{
82
+ reason: RunnerReservationCapacityFailureReason;
83
+ }>;
33
84
  export type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';
34
85
  export type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';
35
86
  export type RunnersRateLimitOutcome = 'allowed' | 'blocked' | 'unavailable';
87
+ export declare function recordProviderRunnerCreatedToControlSession(params: ProviderRunnerLifecycleObservation): void;
88
+ export declare function recordProviderRunnerControlSessionToAssignment(params: ProviderRunnerAssignmentObservation): void;
89
+ export declare function recordProviderRunnerAssignmentToActivation(params: ProviderRunnerLifecycleObservation): void;
90
+ export declare function recordProviderRunnerActivationToFirstClaim(params: ProviderRunnerLifecycleObservation): void;
91
+ export declare function recordJobExecutionQueueTime(params: JobExecutionQueueTimeObservation): void;
92
+ export declare function recordProviderRunnerAssignmentRejected(params: {
93
+ reason: RunnerAssignmentRejectionReason;
94
+ surface: RunnerAssignmentSurface;
95
+ }): void;
36
96
  export declare function recordRunnerReservationPromotionFailure(reason: RunnerReservationPromotionFailureReason): void;
97
+ export declare function recordRunnerActivationTokenNotIssued(params: {
98
+ reason: RunnerActivationTokenNotIssuedReason;
99
+ surface: RunnerActivationTokenNotIssuedSurface;
100
+ }): void;
101
+ export declare function recordRunnerReservationCapacityFailure(reason: RunnerReservationCapacityFailureReason, count: number): void;
37
102
  export declare function recordRunnersRateLimitCheck(params: {
38
103
  action: RunnersRateLimitAction;
39
104
  scope: RunnersRateLimitScope;
40
105
  outcome: RunnersRateLimitOutcome;
41
106
  }): void;
42
107
  export declare function recordRunnersRateLimitPruneFailure(): void;
108
+ export declare function recordProviderRunnerActivationOutcome(params: {
109
+ outcome: 'reaped' | 'rebound';
110
+ count?: number;
111
+ }): void;
112
+ export {};
43
113
  //# sourceMappingURL=instance.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/metrics/instance.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,yBAAyB,sEAKrC,CAAC;AAEF,eAAO,MAAM,wBAAwB;aAAiC,SAAS,GAAG,OAAO;EAGxF,CAAC;AAEF,eAAO,MAAM,6BAA6B,sEAGzC,CAAC;AAEF,eAAO,MAAM,yBAAyB;WAC7B,UAAU,GAAG,SAAS,GAAG,UAAU,GAAG,SAAS,GAAG,QAAQ,GAAG,YAAY;EAGhF,CAAC;AAEH,eAAO,MAAM,4BAA4B;aAC9B,UAAU,GAAG,UAAU;EAGhC,CAAC;AAEH,eAAO,MAAM,2BAA2B,sEAGvC,CAAC;AAEF,eAAO,MAAM,yBAAyB,sEAKrC,CAAC;AAEF,eAAO,MAAM,kCAAkC;mBAC9B,MAAM;WACd,UAAU,GAAG,SAAS;eAClB,gBAAgB,GAAG,mBAAmB;EAIjD,CAAC;AAEH,eAAO,MAAM,gCAAgC,sEAG5C,CAAC;AAEF,eAAO,MAAM,mCAAmC,sEAM/C,CAAC;AAEF,eAAO,MAAM,wCAAwC;aAC1C,aAAa,GAAG,WAAW;YAC5B,eAAe,GAAG,gBAAgB;EAG1C,CAAC;AAEH,eAAO,MAAM,yCAAyC;YAC5C,eAAe;EAGvB,CAAC;AAEH,eAAO,MAAM,wBAAwB,sEAGpC,CAAC;AAEF,MAAM,MAAM,uCAAuC,GAC/C,qBAAqB,GACrB,uBAAuB,GACvB,kBAAkB,GAClB,gBAAgB,CAAC;AAErB,eAAO,MAAM,sCAAsC;YACzC,uCAAuC;EAG/C,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,kBAAkB,GAAG,oBAAoB,CAAC;AAC/E,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,iBAAiB,CAAC;AACtE,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,SAAS,GAAG,aAAa,CAAC;AAsB5E,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,uCAAuC,GAC9C,IAAI,CAEN;AAED,wBAAgB,2BAA2B,CAAC,MAAM,EAAE;IAClD,MAAM,EAAE,sBAAsB,CAAC;IAC/B,KAAK,EAAE,qBAAqB,CAAC;IAC7B,OAAO,EAAE,uBAAuB,CAAC;CAClC,GAAG,IAAI,CAQP;AAED,wBAAgB,kCAAkC,IAAI,IAAI,CAEzD"}
1
+ {"version":3,"file":"instance.d.ts","sourceRoot":"","sources":["../../src/metrics/instance.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,96 @@
1
- import { instanceMetrics } from '@shipfox/node-opentelemetry';
1
+ import { instanceMetrics, logger } from '@shipfox/node-opentelemetry';
2
2
  const meter = instanceMetrics.getMeter('runners');
3
+ export const UNKNOWN_PROVIDER_KIND = 'unknown';
4
+ const lifecycleDurationBuckets = {
5
+ long: [
6
+ 100,
7
+ 500,
8
+ 1_000,
9
+ 5_000,
10
+ 10_000,
11
+ 15_000,
12
+ 20_000,
13
+ 30_000,
14
+ 45_000,
15
+ 60_000,
16
+ 90_000,
17
+ 120_000,
18
+ 300_000,
19
+ 600_000
20
+ ],
21
+ short: [
22
+ 10,
23
+ 25,
24
+ 50,
25
+ 100,
26
+ 250,
27
+ 500,
28
+ 1_000,
29
+ 5_000,
30
+ 10_000
31
+ ]
32
+ };
33
+ const queueTimeBucketsMilliseconds = [
34
+ 100,
35
+ 500,
36
+ 1_000,
37
+ 5_000,
38
+ 10_000,
39
+ 15_000,
40
+ 20_000,
41
+ 30_000,
42
+ 45_000,
43
+ 60_000,
44
+ 90_000,
45
+ 120_000,
46
+ 300_000,
47
+ 600_000,
48
+ 900_000,
49
+ 1_800_000,
50
+ 3_600_000,
51
+ 7_200_000,
52
+ 14_400_000
53
+ ];
54
+ // Keep the ordered lifecycle phases as separate histograms so long boot times do not flatten
55
+ // short handoffs. Assignment is the only phase with a surface dimension.
56
+ export const providerRunnerCreatedToControlSessionDuration = meter.createHistogram('runners_provider_runner_created_to_control_session', {
57
+ description: 'Provider runner row creation to control-session creation duration',
58
+ unit: 'ms',
59
+ advice: {
60
+ explicitBucketBoundaries: lifecycleDurationBuckets.long
61
+ }
62
+ });
63
+ export const providerRunnerControlSessionToAssignmentDuration = meter.createHistogram('runners_provider_runner_control_session_to_assignment', {
64
+ description: 'Provider runner control-session creation to reservation assignment duration',
65
+ unit: 'ms',
66
+ advice: {
67
+ explicitBucketBoundaries: lifecycleDurationBuckets.long
68
+ }
69
+ });
70
+ export const providerRunnerAssignmentToActivationDuration = meter.createHistogram('runners_provider_runner_assignment_to_activation', {
71
+ description: 'Provider runner reservation assignment to workspace runner-session creation duration',
72
+ unit: 'ms',
73
+ advice: {
74
+ explicitBucketBoundaries: lifecycleDurationBuckets.short
75
+ }
76
+ });
77
+ export const providerRunnerActivationToFirstClaimDuration = meter.createHistogram('runners_provider_runner_activation_to_first_claim', {
78
+ description: 'Provider runner workspace runner-session creation to first job claim duration',
79
+ unit: 'ms',
80
+ advice: {
81
+ explicitBucketBoundaries: lifecycleDurationBuckets.short
82
+ }
83
+ });
84
+ export const jobExecutionQueueTimeDuration = meter.createHistogram('runners_job_execution_queue_time', {
85
+ description: 'Job execution pending queue duration from enqueue to runner claim',
86
+ unit: 'ms',
87
+ advice: {
88
+ explicitBucketBoundaries: queueTimeBucketsMilliseconds
89
+ }
90
+ });
91
+ export const providerRunnerAssignmentRejectedCount = meter.createCounter('runners_provider_runner_assignment_rejected', {
92
+ description: 'Provider runner assignment operations rejected by bounded reason and surface'
93
+ });
3
94
  export const jobExecutionEnqueuedCount = meter.createCounter('runners_job_execution_enqueued', {
4
95
  description: 'Job executions added to the pending queue'
5
96
  });
@@ -15,6 +106,9 @@ export const providerRunnerReportCount = meter.createCounter('runners_provider_r
15
106
  export const runnerBootstrapExchangeCount = meter.createCounter('runners_runner_bootstrap_exchange', {
16
107
  description: 'Runner bootstrap-token exchanges by outcome'
17
108
  });
109
+ export const runnerActivationTokenNotIssuedCount = meter.createCounter('runners_runner_activation_token_not_issued', {
110
+ description: 'Runner activation token issuance skips by reason and surface'
111
+ });
18
112
  export const runnerControlHeartbeatCount = meter.createCounter('runners_runner_control_heartbeat', {
19
113
  description: 'Pre-workspace runner-control heartbeats accepted'
20
114
  });
@@ -36,12 +130,18 @@ export const providerRunnerTerminateIntentIssuedCount = meter.createCounter('run
36
130
  export const providerRunnerTerminateIntentHonoredCount = meter.createCounter('runners_provider_runner_terminate_intent_honored', {
37
131
  description: 'Provisioned runner terminate intents honored by first transition to terminated'
38
132
  });
133
+ export const providerRunnerActivationOutcomeCount = meter.createCounter('runners_provider_runner_activation_outcome', {
134
+ description: 'Demand-backed runner activation outcomes by recovery action'
135
+ });
39
136
  export const reservationReleasedCount = meter.createCounter('runners_reservation_released', {
40
137
  description: 'Reservation units released from terminal provisioned runner reports'
41
138
  });
42
139
  export const runnerReservationPromotionFailureCount = meter.createCounter('runners_reservation_promotion_failures', {
43
140
  description: 'Runner reservation promotion failures during enrollment by reason'
44
141
  });
142
+ export const runnerReservationCapacityFailureCount = meter.createCounter('runners_reservation_capacity_failures', {
143
+ description: 'Runner reservation admission shortfalls by reason'
144
+ });
45
145
  const rateLimitCheckCount = meter.createCounter('runners_rate_limit_checks', {
46
146
  description: 'Runners rate limit checks by action, scope, and outcome'
47
147
  });
@@ -55,11 +155,66 @@ function recordMetric(record) {
55
155
  // Metrics must not affect runner or provisioner request outcomes.
56
156
  }
57
157
  }
158
+ function resolveProviderRunnerMetricProvider(params) {
159
+ if (params.provider) return params.provider;
160
+ logger().debug({
161
+ runnerInstanceId: params.runnerInstanceId
162
+ }, 'Provider runner metric missing provider kind');
163
+ return UNKNOWN_PROVIDER_KIND;
164
+ }
165
+ export function recordProviderRunnerCreatedToControlSession(params) {
166
+ if (params.durationMilliseconds < 0) return;
167
+ recordMetric(()=>providerRunnerCreatedToControlSessionDuration.record(params.durationMilliseconds, {
168
+ provider: resolveProviderRunnerMetricProvider(params),
169
+ launch_kind: params.launchKind
170
+ }));
171
+ }
172
+ export function recordProviderRunnerControlSessionToAssignment(params) {
173
+ if (params.durationMilliseconds < 0) return;
174
+ recordMetric(()=>providerRunnerControlSessionToAssignmentDuration.record(params.durationMilliseconds, {
175
+ provider: resolveProviderRunnerMetricProvider(params),
176
+ launch_kind: params.launchKind,
177
+ surface: params.surface
178
+ }));
179
+ }
180
+ export function recordProviderRunnerAssignmentToActivation(params) {
181
+ if (params.durationMilliseconds < 0) return;
182
+ recordMetric(()=>providerRunnerAssignmentToActivationDuration.record(params.durationMilliseconds, {
183
+ provider: resolveProviderRunnerMetricProvider(params),
184
+ launch_kind: params.launchKind
185
+ }));
186
+ }
187
+ export function recordProviderRunnerActivationToFirstClaim(params) {
188
+ if (params.durationMilliseconds < 0) return;
189
+ recordMetric(()=>providerRunnerActivationToFirstClaimDuration.record(params.durationMilliseconds, {
190
+ provider: resolveProviderRunnerMetricProvider(params),
191
+ launch_kind: params.launchKind
192
+ }));
193
+ }
194
+ export function recordJobExecutionQueueTime(params) {
195
+ if (params.durationMilliseconds < 0) return;
196
+ recordMetric(()=>jobExecutionQueueTimeDuration.record(params.durationMilliseconds, {
197
+ provider: params.provider ?? UNKNOWN_PROVIDER_KIND,
198
+ launch_kind: params.launchKind
199
+ }));
200
+ }
201
+ export function recordProviderRunnerAssignmentRejected(params) {
202
+ recordMetric(()=>providerRunnerAssignmentRejectedCount.add(1, params));
203
+ }
58
204
  export function recordRunnerReservationPromotionFailure(reason) {
59
205
  recordMetric(()=>runnerReservationPromotionFailureCount.add(1, {
60
206
  reason
61
207
  }));
62
208
  }
209
+ export function recordRunnerActivationTokenNotIssued(params) {
210
+ recordMetric(()=>runnerActivationTokenNotIssuedCount.add(1, params));
211
+ }
212
+ export function recordRunnerReservationCapacityFailure(reason, count) {
213
+ if (count <= 0) return;
214
+ recordMetric(()=>runnerReservationCapacityFailureCount.add(count, {
215
+ reason
216
+ }));
217
+ }
63
218
  export function recordRunnersRateLimitCheck(params) {
64
219
  recordMetric(()=>rateLimitCheckCount.add(1, {
65
220
  action: params.action,
@@ -70,5 +225,10 @@ export function recordRunnersRateLimitCheck(params) {
70
225
  export function recordRunnersRateLimitPruneFailure() {
71
226
  recordMetric(()=>rateLimitPruneFailureCount.add(1));
72
227
  }
228
+ export function recordProviderRunnerActivationOutcome(params) {
229
+ recordMetric(()=>providerRunnerActivationOutcomeCount.add(params.count ?? 1, {
230
+ outcome: params.outcome
231
+ }));
232
+ }
73
233
 
74
234
  //# sourceMappingURL=instance.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/instance.ts"],"sourcesContent":["import {instanceMetrics} from '@shipfox/node-opentelemetry';\n\nconst meter = instanceMetrics.getMeter('runners');\n\nexport const jobExecutionEnqueuedCount = meter.createCounter<Record<string, never>>(\n 'runners_job_execution_enqueued',\n {\n description: 'Job executions added to the pending queue',\n },\n);\n\nexport const jobExecutionClaimedCount = meter.createCounter<{outcome: 'claimed' | 'empty'}>(\n 'runners_job_execution_claimed',\n {description: 'Job execution claim attempts by outcome'},\n);\n\nexport const jobExecutionLeaseExpiredCount = meter.createCounter<Record<string, never>>(\n 'runners_job_execution_lease_expired',\n {description: 'Job execution leases reaped after passing the heartbeat threshold'},\n);\n\nexport const providerRunnerReportCount = meter.createCounter<{\n state: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'terminated';\n}>('runners_provider_runner_reported', {\n description: 'Provisioned runner lifecycle reports accepted by state',\n});\n\nexport const runnerBootstrapExchangeCount = meter.createCounter<{\n outcome: 'accepted' | 'rejected';\n}>('runners_runner_bootstrap_exchange', {\n description: 'Runner bootstrap-token exchanges by outcome',\n});\n\nexport const runnerControlHeartbeatCount = meter.createCounter<Record<string, never>>(\n 'runners_runner_control_heartbeat',\n {description: 'Pre-workspace runner-control heartbeats accepted'},\n);\n\nexport const providerRunnerReapedCount = meter.createCounter<Record<string, never>>(\n 'runners_provider_runner_reaped',\n {\n description: 'Stale provisioned runners marked failed by backend maintenance',\n },\n);\n\nexport const providerRunnerCountDivergenceCount = meter.createCounter<{\n template_key?: string;\n state: 'starting' | 'running';\n direction: 'backend-higher' | 'advertised-higher';\n}>('runners_provider_runner_count_divergence', {\n description:\n 'Absolute difference between provisioner-advertised and backend-observed provisioned runner counts',\n});\n\nexport const providerRunnerReconcileCallCount = meter.createCounter<Record<string, never>>(\n 'runners_provider_runner_reconcile_called',\n {description: 'Provisioned runner reconcile calls completed successfully'},\n);\n\nexport const providerRunnerAbsentTerminatedCount = meter.createCounter<Record<string, never>>(\n 'runners_provider_runner_absent_terminated',\n {\n description:\n 'Owned provisioned runners marked terminated because they were absent from reconcile',\n },\n);\n\nexport const providerRunnerTerminateIntentIssuedCount = meter.createCounter<{\n surface: 'poll-demand' | 'reconcile';\n reason: 'job-cancelled' | 'terminal-state';\n}>('runners_provider_runner_terminate_intent_issued', {\n description: 'Provisioned runner terminate intents returned to provisioners',\n});\n\nexport const providerRunnerTerminateIntentHonoredCount = meter.createCounter<{\n reason: 'job-cancelled';\n}>('runners_provider_runner_terminate_intent_honored', {\n description: 'Provisioned runner terminate intents honored by first transition to terminated',\n});\n\nexport const reservationReleasedCount = meter.createCounter<Record<string, never>>(\n 'runners_reservation_released',\n {description: 'Reservation units released from terminal provisioned runner reports'},\n);\n\nexport type RunnerReservationPromotionFailureReason =\n | 'reservation-expired'\n | 'reservation-not-found'\n | 'already-assigned'\n | 'not-assignable';\n\nexport const runnerReservationPromotionFailureCount = meter.createCounter<{\n reason: RunnerReservationPromotionFailureReason;\n}>('runners_reservation_promotion_failures', {\n description: 'Runner reservation promotion failures during enrollment by reason',\n});\n\nexport type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';\nexport type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';\nexport type RunnersRateLimitOutcome = 'allowed' | 'blocked' | 'unavailable';\n\nconst rateLimitCheckCount = meter.createCounter<{\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n outcome: RunnersRateLimitOutcome;\n}>('runners_rate_limit_checks', {\n description: 'Runners rate limit checks by action, scope, and outcome',\n});\n\nconst rateLimitPruneFailureCount = meter.createCounter('runners_rate_limit_prune_failures', {\n description: 'Runners rate limit prune failures',\n});\n\nfunction recordMetric(record: () => void): void {\n try {\n record();\n } catch {\n // Metrics must not affect runner or provisioner request outcomes.\n }\n}\n\nexport function recordRunnerReservationPromotionFailure(\n reason: RunnerReservationPromotionFailureReason,\n): void {\n recordMetric(() => runnerReservationPromotionFailureCount.add(1, {reason}));\n}\n\nexport function recordRunnersRateLimitCheck(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n outcome: RunnersRateLimitOutcome;\n}): void {\n recordMetric(() =>\n rateLimitCheckCount.add(1, {\n action: params.action,\n scope: params.scope,\n outcome: params.outcome,\n }),\n );\n}\n\nexport function recordRunnersRateLimitPruneFailure(): void {\n recordMetric(() => rateLimitPruneFailureCount.add(1));\n}\n"],"names":["instanceMetrics","meter","getMeter","jobExecutionEnqueuedCount","createCounter","description","jobExecutionClaimedCount","jobExecutionLeaseExpiredCount","providerRunnerReportCount","runnerBootstrapExchangeCount","runnerControlHeartbeatCount","providerRunnerReapedCount","providerRunnerCountDivergenceCount","providerRunnerReconcileCallCount","providerRunnerAbsentTerminatedCount","providerRunnerTerminateIntentIssuedCount","providerRunnerTerminateIntentHonoredCount","reservationReleasedCount","runnerReservationPromotionFailureCount","rateLimitCheckCount","rateLimitPruneFailureCount","recordMetric","record","recordRunnerReservationPromotionFailure","reason","add","recordRunnersRateLimitCheck","params","action","scope","outcome","recordRunnersRateLimitPruneFailure"],"mappings":"AAAA,SAAQA,eAAe,QAAO,8BAA8B;AAE5D,MAAMC,QAAQD,gBAAgBE,QAAQ,CAAC;AAEvC,OAAO,MAAMC,4BAA4BF,MAAMG,aAAa,CAC1D,kCACA;IACEC,aAAa;AACf,GACA;AAEF,OAAO,MAAMC,2BAA2BL,MAAMG,aAAa,CACzD,iCACA;IAACC,aAAa;AAAyC,GACvD;AAEF,OAAO,MAAME,gCAAgCN,MAAMG,aAAa,CAC9D,uCACA;IAACC,aAAa;AAAmE,GACjF;AAEF,OAAO,MAAMG,4BAA4BP,MAAMG,aAAa,CAEzD,oCAAoC;IACrCC,aAAa;AACf,GAAG;AAEH,OAAO,MAAMI,+BAA+BR,MAAMG,aAAa,CAE5D,qCAAqC;IACtCC,aAAa;AACf,GAAG;AAEH,OAAO,MAAMK,8BAA8BT,MAAMG,aAAa,CAC5D,oCACA;IAACC,aAAa;AAAkD,GAChE;AAEF,OAAO,MAAMM,4BAA4BV,MAAMG,aAAa,CAC1D,kCACA;IACEC,aAAa;AACf,GACA;AAEF,OAAO,MAAMO,qCAAqCX,MAAMG,aAAa,CAIlE,4CAA4C;IAC7CC,aACE;AACJ,GAAG;AAEH,OAAO,MAAMQ,mCAAmCZ,MAAMG,aAAa,CACjE,4CACA;IAACC,aAAa;AAA2D,GACzE;AAEF,OAAO,MAAMS,sCAAsCb,MAAMG,aAAa,CACpE,6CACA;IACEC,aACE;AACJ,GACA;AAEF,OAAO,MAAMU,2CAA2Cd,MAAMG,aAAa,CAGxE,mDAAmD;IACpDC,aAAa;AACf,GAAG;AAEH,OAAO,MAAMW,4CAA4Cf,MAAMG,aAAa,CAEzE,oDAAoD;IACrDC,aAAa;AACf,GAAG;AAEH,OAAO,MAAMY,2BAA2BhB,MAAMG,aAAa,CACzD,gCACA;IAACC,aAAa;AAAqE,GACnF;AAQF,OAAO,MAAMa,yCAAyCjB,MAAMG,aAAa,CAEtE,0CAA0C;IAC3CC,aAAa;AACf,GAAG;AAMH,MAAMc,sBAAsBlB,MAAMG,aAAa,CAI5C,6BAA6B;IAC9BC,aAAa;AACf;AAEA,MAAMe,6BAA6BnB,MAAMG,aAAa,CAAC,qCAAqC;IAC1FC,aAAa;AACf;AAEA,SAASgB,aAAaC,MAAkB;IACtC,IAAI;QACFA;IACF,EAAE,OAAM;IACN,kEAAkE;IACpE;AACF;AAEA,OAAO,SAASC,wCACdC,MAA+C;IAE/CH,aAAa,IAAMH,uCAAuCO,GAAG,CAAC,GAAG;YAACD;QAAM;AAC1E;AAEA,OAAO,SAASE,4BAA4BC,MAI3C;IACCN,aAAa,IACXF,oBAAoBM,GAAG,CAAC,GAAG;YACzBG,QAAQD,OAAOC,MAAM;YACrBC,OAAOF,OAAOE,KAAK;YACnBC,SAASH,OAAOG,OAAO;QACzB;AAEJ;AAEA,OAAO,SAASC;IACdV,aAAa,IAAMD,2BAA2BK,GAAG,CAAC;AACpD"}
1
+ {"version":3,"sources":["../../src/metrics/instance.ts"],"sourcesContent":["import {instanceMetrics, logger} from '@shipfox/node-opentelemetry';\nimport type {RunnerAssignmentRejectionReason} from '#core/errors.js';\n\nconst meter = instanceMetrics.getMeter('runners');\n\nexport type RunnerLaunchKind = 'demand' | 'warm' | 'manual';\nexport type RunnerAssignmentSurface = 'provisioner' | 'enrollment';\n\ntype ProviderRunnerLifecycleLabels = {\n provider: string;\n launch_kind: RunnerLaunchKind;\n};\n\ntype ProviderRunnerAssignmentLifecycleLabels = ProviderRunnerLifecycleLabels & {\n surface: RunnerAssignmentSurface;\n};\n\ntype JobExecutionQueueTimeLabels = {\n provider: string;\n launch_kind: RunnerLaunchKind | 'unknown';\n};\n\nexport interface JobExecutionQueueTimeObservation {\n durationMilliseconds: number;\n provider: string | null;\n launchKind: RunnerLaunchKind | 'unknown';\n}\n\nexport interface ProviderRunnerLifecycleObservation {\n durationMilliseconds: number;\n provider: string | null;\n launchKind: RunnerLaunchKind;\n runnerInstanceId?: string;\n}\n\nexport interface ProviderRunnerAssignmentObservation extends ProviderRunnerLifecycleObservation {\n surface: RunnerAssignmentSurface;\n}\n\nexport const UNKNOWN_PROVIDER_KIND = 'unknown';\n\nconst lifecycleDurationBuckets = {\n long: [\n 100, 500, 1_000, 5_000, 10_000, 15_000, 20_000, 30_000, 45_000, 60_000, 90_000, 120_000,\n 300_000, 600_000,\n ],\n short: [10, 25, 50, 100, 250, 500, 1_000, 5_000, 10_000],\n};\n\nconst queueTimeBucketsMilliseconds = [\n 100, 500, 1_000, 5_000, 10_000, 15_000, 20_000, 30_000, 45_000, 60_000, 90_000, 120_000, 300_000,\n 600_000, 900_000, 1_800_000, 3_600_000, 7_200_000, 14_400_000,\n];\n\n// Keep the ordered lifecycle phases as separate histograms so long boot times do not flatten\n// short handoffs. Assignment is the only phase with a surface dimension.\nexport const providerRunnerCreatedToControlSessionDuration =\n meter.createHistogram<ProviderRunnerLifecycleLabels>(\n 'runners_provider_runner_created_to_control_session',\n {\n description: 'Provider runner row creation to control-session creation duration',\n unit: 'ms',\n advice: {explicitBucketBoundaries: lifecycleDurationBuckets.long},\n },\n );\n\nexport const providerRunnerControlSessionToAssignmentDuration =\n meter.createHistogram<ProviderRunnerAssignmentLifecycleLabels>(\n 'runners_provider_runner_control_session_to_assignment',\n {\n description: 'Provider runner control-session creation to reservation assignment duration',\n unit: 'ms',\n advice: {explicitBucketBoundaries: lifecycleDurationBuckets.long},\n },\n );\n\nexport const providerRunnerAssignmentToActivationDuration =\n meter.createHistogram<ProviderRunnerLifecycleLabels>(\n 'runners_provider_runner_assignment_to_activation',\n {\n description:\n 'Provider runner reservation assignment to workspace runner-session creation duration',\n unit: 'ms',\n advice: {explicitBucketBoundaries: lifecycleDurationBuckets.short},\n },\n );\n\nexport const providerRunnerActivationToFirstClaimDuration =\n meter.createHistogram<ProviderRunnerLifecycleLabels>(\n 'runners_provider_runner_activation_to_first_claim',\n {\n description: 'Provider runner workspace runner-session creation to first job claim duration',\n unit: 'ms',\n advice: {explicitBucketBoundaries: lifecycleDurationBuckets.short},\n },\n );\n\nexport const jobExecutionQueueTimeDuration = meter.createHistogram<JobExecutionQueueTimeLabels>(\n 'runners_job_execution_queue_time',\n {\n description: 'Job execution pending queue duration from enqueue to runner claim',\n unit: 'ms',\n advice: {explicitBucketBoundaries: queueTimeBucketsMilliseconds},\n },\n);\n\nexport const providerRunnerAssignmentRejectedCount = meter.createCounter<{\n reason: RunnerAssignmentRejectionReason;\n surface: RunnerAssignmentSurface;\n}>('runners_provider_runner_assignment_rejected', {\n description: 'Provider runner assignment operations rejected by bounded reason and surface',\n});\n\nexport const jobExecutionEnqueuedCount = meter.createCounter<Record<string, never>>(\n 'runners_job_execution_enqueued',\n {\n description: 'Job executions added to the pending queue',\n },\n);\n\nexport const jobExecutionClaimedCount = meter.createCounter<{outcome: 'claimed' | 'empty'}>(\n 'runners_job_execution_claimed',\n {description: 'Job execution claim attempts by outcome'},\n);\n\nexport const jobExecutionLeaseExpiredCount = meter.createCounter<Record<string, never>>(\n 'runners_job_execution_lease_expired',\n {description: 'Job execution leases reaped after passing the heartbeat threshold'},\n);\n\nexport const providerRunnerReportCount = meter.createCounter<{\n state: 'starting' | 'running' | 'stopping' | 'stopped' | 'failed' | 'terminated';\n}>('runners_provider_runner_reported', {\n description: 'Provisioned runner lifecycle reports accepted by state',\n});\n\nexport const runnerBootstrapExchangeCount = meter.createCounter<{\n outcome: 'accepted' | 'rejected';\n}>('runners_runner_bootstrap_exchange', {\n description: 'Runner bootstrap-token exchanges by outcome',\n});\n\nexport type RunnerActivationTokenNotIssuedReason =\n | 'runner-not-found'\n | 'missing-workspace'\n | 'existing-session'\n | 'not-running';\n\nexport type RunnerActivationTokenNotIssuedSurface = 'enrollment' | 'poll';\n\nexport const runnerActivationTokenNotIssuedCount = meter.createCounter<{\n reason: RunnerActivationTokenNotIssuedReason;\n surface: RunnerActivationTokenNotIssuedSurface;\n}>('runners_runner_activation_token_not_issued', {\n description: 'Runner activation token issuance skips by reason and surface',\n});\n\nexport const runnerControlHeartbeatCount = meter.createCounter<Record<string, never>>(\n 'runners_runner_control_heartbeat',\n {description: 'Pre-workspace runner-control heartbeats accepted'},\n);\n\nexport const providerRunnerReapedCount = meter.createCounter<Record<string, never>>(\n 'runners_provider_runner_reaped',\n {\n description: 'Stale provisioned runners marked failed by backend maintenance',\n },\n);\n\nexport const providerRunnerCountDivergenceCount = meter.createCounter<{\n template_key?: string;\n state: 'starting' | 'running';\n direction: 'backend-higher' | 'advertised-higher';\n}>('runners_provider_runner_count_divergence', {\n description:\n 'Absolute difference between provisioner-advertised and backend-observed provisioned runner counts',\n});\n\nexport const providerRunnerReconcileCallCount = meter.createCounter<Record<string, never>>(\n 'runners_provider_runner_reconcile_called',\n {description: 'Provisioned runner reconcile calls completed successfully'},\n);\n\nexport const providerRunnerAbsentTerminatedCount = meter.createCounter<Record<string, never>>(\n 'runners_provider_runner_absent_terminated',\n {\n description:\n 'Owned provisioned runners marked terminated because they were absent from reconcile',\n },\n);\n\nexport const providerRunnerTerminateIntentIssuedCount = meter.createCounter<{\n surface: 'poll-demand' | 'reconcile';\n reason: 'activation-timeout' | 'job-cancelled' | 'terminal-state';\n}>('runners_provider_runner_terminate_intent_issued', {\n description: 'Provisioned runner terminate intents returned to provisioners',\n});\n\nexport const providerRunnerTerminateIntentHonoredCount = meter.createCounter<{\n reason: 'activation-timeout' | 'job-cancelled';\n}>('runners_provider_runner_terminate_intent_honored', {\n description: 'Provisioned runner terminate intents honored by first transition to terminated',\n});\n\nexport const providerRunnerActivationOutcomeCount = meter.createCounter<{\n outcome: 'reaped' | 'rebound';\n}>('runners_provider_runner_activation_outcome', {\n description: 'Demand-backed runner activation outcomes by recovery action',\n});\n\nexport const reservationReleasedCount = meter.createCounter<Record<string, never>>(\n 'runners_reservation_released',\n {description: 'Reservation units released from terminal provisioned runner reports'},\n);\n\nexport type RunnerReservationPromotionFailureReason =\n | 'reservation-expired'\n | 'reservation-not-found'\n | 'already-assigned'\n | 'not-assignable';\n\nexport const runnerReservationPromotionFailureCount = meter.createCounter<{\n reason: RunnerReservationPromotionFailureReason;\n}>('runners_reservation_promotion_failures', {\n description: 'Runner reservation promotion failures during enrollment by reason',\n});\n\nexport type RunnerReservationCapacityFailureReason =\n | 'reservation-not-found'\n | 'reservation-kind-mismatch'\n | 'reservation-expired'\n | 'capacity-exhausted';\n\nexport const runnerReservationCapacityFailureCount = meter.createCounter<{\n reason: RunnerReservationCapacityFailureReason;\n}>('runners_reservation_capacity_failures', {\n description: 'Runner reservation admission shortfalls by reason',\n});\n\nexport type RunnersRateLimitAction = 'provisioner-mint' | 'ephemeral-register';\nexport type RunnersRateLimitScope = 'provisioner' | 'ephemeral-token';\nexport type RunnersRateLimitOutcome = 'allowed' | 'blocked' | 'unavailable';\n\nconst rateLimitCheckCount = meter.createCounter<{\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n outcome: RunnersRateLimitOutcome;\n}>('runners_rate_limit_checks', {\n description: 'Runners rate limit checks by action, scope, and outcome',\n});\n\nconst rateLimitPruneFailureCount = meter.createCounter('runners_rate_limit_prune_failures', {\n description: 'Runners rate limit prune failures',\n});\n\nfunction recordMetric(record: () => void): void {\n try {\n record();\n } catch {\n // Metrics must not affect runner or provisioner request outcomes.\n }\n}\n\nfunction resolveProviderRunnerMetricProvider(params: {\n provider: string | null;\n runnerInstanceId?: string;\n}): string {\n if (params.provider) return params.provider;\n logger().debug(\n {runnerInstanceId: params.runnerInstanceId},\n 'Provider runner metric missing provider kind',\n );\n return UNKNOWN_PROVIDER_KIND;\n}\n\nexport function recordProviderRunnerCreatedToControlSession(\n params: ProviderRunnerLifecycleObservation,\n): void {\n if (params.durationMilliseconds < 0) return;\n recordMetric(() =>\n providerRunnerCreatedToControlSessionDuration.record(params.durationMilliseconds, {\n provider: resolveProviderRunnerMetricProvider(params),\n launch_kind: params.launchKind,\n }),\n );\n}\n\nexport function recordProviderRunnerControlSessionToAssignment(\n params: ProviderRunnerAssignmentObservation,\n): void {\n if (params.durationMilliseconds < 0) return;\n recordMetric(() =>\n providerRunnerControlSessionToAssignmentDuration.record(params.durationMilliseconds, {\n provider: resolveProviderRunnerMetricProvider(params),\n launch_kind: params.launchKind,\n surface: params.surface,\n }),\n );\n}\n\nexport function recordProviderRunnerAssignmentToActivation(\n params: ProviderRunnerLifecycleObservation,\n): void {\n if (params.durationMilliseconds < 0) return;\n recordMetric(() =>\n providerRunnerAssignmentToActivationDuration.record(params.durationMilliseconds, {\n provider: resolveProviderRunnerMetricProvider(params),\n launch_kind: params.launchKind,\n }),\n );\n}\n\nexport function recordProviderRunnerActivationToFirstClaim(\n params: ProviderRunnerLifecycleObservation,\n): void {\n if (params.durationMilliseconds < 0) return;\n recordMetric(() =>\n providerRunnerActivationToFirstClaimDuration.record(params.durationMilliseconds, {\n provider: resolveProviderRunnerMetricProvider(params),\n launch_kind: params.launchKind,\n }),\n );\n}\n\nexport function recordJobExecutionQueueTime(params: JobExecutionQueueTimeObservation): void {\n if (params.durationMilliseconds < 0) return;\n recordMetric(() =>\n jobExecutionQueueTimeDuration.record(params.durationMilliseconds, {\n provider: params.provider ?? UNKNOWN_PROVIDER_KIND,\n launch_kind: params.launchKind,\n }),\n );\n}\n\nexport function recordProviderRunnerAssignmentRejected(params: {\n reason: RunnerAssignmentRejectionReason;\n surface: RunnerAssignmentSurface;\n}): void {\n recordMetric(() => providerRunnerAssignmentRejectedCount.add(1, params));\n}\n\nexport function recordRunnerReservationPromotionFailure(\n reason: RunnerReservationPromotionFailureReason,\n): void {\n recordMetric(() => runnerReservationPromotionFailureCount.add(1, {reason}));\n}\n\nexport function recordRunnerActivationTokenNotIssued(params: {\n reason: RunnerActivationTokenNotIssuedReason;\n surface: RunnerActivationTokenNotIssuedSurface;\n}): void {\n recordMetric(() => runnerActivationTokenNotIssuedCount.add(1, params));\n}\n\nexport function recordRunnerReservationCapacityFailure(\n reason: RunnerReservationCapacityFailureReason,\n count: number,\n): void {\n if (count <= 0) return;\n recordMetric(() => runnerReservationCapacityFailureCount.add(count, {reason}));\n}\n\nexport function recordRunnersRateLimitCheck(params: {\n action: RunnersRateLimitAction;\n scope: RunnersRateLimitScope;\n outcome: RunnersRateLimitOutcome;\n}): void {\n recordMetric(() =>\n rateLimitCheckCount.add(1, {\n action: params.action,\n scope: params.scope,\n outcome: params.outcome,\n }),\n );\n}\n\nexport function recordRunnersRateLimitPruneFailure(): void {\n recordMetric(() => rateLimitPruneFailureCount.add(1));\n}\n\nexport function recordProviderRunnerActivationOutcome(params: {\n outcome: 'reaped' | 'rebound';\n count?: number;\n}): void {\n recordMetric(() =>\n providerRunnerActivationOutcomeCount.add(params.count ?? 1, {outcome: params.outcome}),\n );\n}\n"],"names":["instanceMetrics","logger","meter","getMeter","UNKNOWN_PROVIDER_KIND","lifecycleDurationBuckets","long","short","queueTimeBucketsMilliseconds","providerRunnerCreatedToControlSessionDuration","createHistogram","description","unit","advice","explicitBucketBoundaries","providerRunnerControlSessionToAssignmentDuration","providerRunnerAssignmentToActivationDuration","providerRunnerActivationToFirstClaimDuration","jobExecutionQueueTimeDuration","providerRunnerAssignmentRejectedCount","createCounter","jobExecutionEnqueuedCount","jobExecutionClaimedCount","jobExecutionLeaseExpiredCount","providerRunnerReportCount","runnerBootstrapExchangeCount","runnerActivationTokenNotIssuedCount","runnerControlHeartbeatCount","providerRunnerReapedCount","providerRunnerCountDivergenceCount","providerRunnerReconcileCallCount","providerRunnerAbsentTerminatedCount","providerRunnerTerminateIntentIssuedCount","providerRunnerTerminateIntentHonoredCount","providerRunnerActivationOutcomeCount","reservationReleasedCount","runnerReservationPromotionFailureCount","runnerReservationCapacityFailureCount","rateLimitCheckCount","rateLimitPruneFailureCount","recordMetric","record","resolveProviderRunnerMetricProvider","params","provider","debug","runnerInstanceId","recordProviderRunnerCreatedToControlSession","durationMilliseconds","launch_kind","launchKind","recordProviderRunnerControlSessionToAssignment","surface","recordProviderRunnerAssignmentToActivation","recordProviderRunnerActivationToFirstClaim","recordJobExecutionQueueTime","recordProviderRunnerAssignmentRejected","add","recordRunnerReservationPromotionFailure","reason","recordRunnerActivationTokenNotIssued","recordRunnerReservationCapacityFailure","count","recordRunnersRateLimitCheck","action","scope","outcome","recordRunnersRateLimitPruneFailure","recordProviderRunnerActivationOutcome"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/metrics/service.ts"],"names":[],"mappings":"AAKA,wBAAgB,6BAA6B,IAAI,IAAI,CAoCpD"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/metrics/service.ts"],"names":[],"mappings":"AAeA,wBAAgB,6BAA6B,IAAI,IAAI,CAyEpD"}
@@ -1,7 +1,7 @@
1
1
  import { getServiceMetricsProvider } from '@shipfox/node-opentelemetry';
2
2
  import { config } from '#config.js';
3
3
  import { getJobExecutionQueueDepth } from '#db/job-executions.js';
4
- import { countStaleEnrolledRunnerInstances } from '#db/runner-instances.js';
4
+ import { countStaleEnrolledRunnerInstances, listProviderRunnerByPhaseMetrics } from '#db/runner-instances.js';
5
5
  export function registerRunnersServiceMetrics() {
6
6
  const meter = getServiceMetricsProvider().getMeter('runners');
7
7
  const pendingJobExecutions = meter.createObservableGauge('runners_pending_job_executions', {
@@ -13,12 +13,20 @@ export function registerRunnersServiceMetrics() {
13
13
  const enrolledRunnersWithoutRecentReport = meter.createObservableGauge('runners_enrolled_without_recent_report', {
14
14
  description: 'Running enrolled runners with a live control session, no workspace or runner session, and no recent provisioner report after the stale-runner grace window'
15
15
  });
16
+ const providerRunnersByPhase = meter.createObservableGauge('runners_provider_runner_by_phase', {
17
+ description: 'Provider runners by lifecycle phase, including idle runners without an active assignment'
18
+ });
19
+ const providerRunnersByPhaseOldestAge = meter.createObservableGauge('runners_provider_runner_by_phase_oldest_age', {
20
+ description: 'Oldest provider runner age by lifecycle phase',
21
+ unit: 'ms'
22
+ });
16
23
  meter.addBatchObservableCallback(async (observer)=>{
17
- const [depthResult, staleEnrolledRunnerCountResult] = await Promise.allSettled([
24
+ const [depthResult, staleEnrolledRunnerCountResult, providerRunnersByPhaseResult] = await Promise.allSettled([
18
25
  getJobExecutionQueueDepth(),
19
26
  countStaleEnrolledRunnerInstances({
20
27
  graceSeconds: config.RUNNER_STALE_PROVISIONED_RUNNER_THRESHOLD_SECONDS
21
- })
28
+ }),
29
+ listProviderRunnerByPhaseMetrics()
22
30
  ]);
23
31
  if (depthResult.status === 'fulfilled') {
24
32
  observer.observe(pendingJobExecutions, depthResult.value.pendingJobExecutions);
@@ -27,10 +35,23 @@ export function registerRunnersServiceMetrics() {
27
35
  if (staleEnrolledRunnerCountResult.status === 'fulfilled') {
28
36
  observer.observe(enrolledRunnersWithoutRecentReport, staleEnrolledRunnerCountResult.value);
29
37
  }
38
+ if (providerRunnersByPhaseResult.status === 'fulfilled') {
39
+ for (const metric of providerRunnersByPhaseResult.value){
40
+ const attributes = {
41
+ phase: metric.phase,
42
+ provider: metric.provider,
43
+ launch_kind: metric.launchKind
44
+ };
45
+ observer.observe(providerRunnersByPhase, metric.count, attributes);
46
+ observer.observe(providerRunnersByPhaseOldestAge, metric.oldestAgeMilliseconds, attributes);
47
+ }
48
+ }
30
49
  }, [
31
50
  pendingJobExecutions,
32
51
  runningJobExecutions,
33
- enrolledRunnersWithoutRecentReport
52
+ enrolledRunnersWithoutRecentReport,
53
+ providerRunnersByPhase,
54
+ providerRunnersByPhaseOldestAge
34
55
  ]);
35
56
  }
36
57
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/metrics/service.ts"],"sourcesContent":["import {getServiceMetricsProvider} from '@shipfox/node-opentelemetry';\nimport {config} from '#config.js';\nimport {getJobExecutionQueueDepth} from '#db/job-executions.js';\nimport {countStaleEnrolledRunnerInstances} from '#db/runner-instances.js';\n\nexport function registerRunnersServiceMetrics(): void {\n const meter = getServiceMetricsProvider().getMeter('runners');\n\n const pendingJobExecutions = meter.createObservableGauge('runners_pending_job_executions', {\n description: 'Job executions currently waiting in the queue to be claimed',\n });\n const runningJobExecutions = meter.createObservableGauge('runners_running_job_executions', {\n description: 'Job executions currently claimed by a runner and in progress',\n });\n const enrolledRunnersWithoutRecentReport = meter.createObservableGauge(\n 'runners_enrolled_without_recent_report',\n {\n description:\n 'Running enrolled runners with a live control session, no workspace or runner session, and no recent provisioner report after the stale-runner grace window',\n },\n );\n\n meter.addBatchObservableCallback(\n async (observer) => {\n const [depthResult, staleEnrolledRunnerCountResult] = await Promise.allSettled([\n getJobExecutionQueueDepth(),\n countStaleEnrolledRunnerInstances({\n graceSeconds: config.RUNNER_STALE_PROVISIONED_RUNNER_THRESHOLD_SECONDS,\n }),\n ]);\n\n if (depthResult.status === 'fulfilled') {\n observer.observe(pendingJobExecutions, depthResult.value.pendingJobExecutions);\n observer.observe(runningJobExecutions, depthResult.value.runningJobExecutions);\n }\n if (staleEnrolledRunnerCountResult.status === 'fulfilled') {\n observer.observe(enrolledRunnersWithoutRecentReport, staleEnrolledRunnerCountResult.value);\n }\n },\n [pendingJobExecutions, runningJobExecutions, enrolledRunnersWithoutRecentReport],\n );\n}\n"],"names":["getServiceMetricsProvider","config","getJobExecutionQueueDepth","countStaleEnrolledRunnerInstances","registerRunnersServiceMetrics","meter","getMeter","pendingJobExecutions","createObservableGauge","description","runningJobExecutions","enrolledRunnersWithoutRecentReport","addBatchObservableCallback","observer","depthResult","staleEnrolledRunnerCountResult","Promise","allSettled","graceSeconds","RUNNER_STALE_PROVISIONED_RUNNER_THRESHOLD_SECONDS","status","observe","value"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,8BAA8B;AACtE,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,yBAAyB,QAAO,wBAAwB;AAChE,SAAQC,iCAAiC,QAAO,0BAA0B;AAE1E,OAAO,SAASC;IACd,MAAMC,QAAQL,4BAA4BM,QAAQ,CAAC;IAEnD,MAAMC,uBAAuBF,MAAMG,qBAAqB,CAAC,kCAAkC;QACzFC,aAAa;IACf;IACA,MAAMC,uBAAuBL,MAAMG,qBAAqB,CAAC,kCAAkC;QACzFC,aAAa;IACf;IACA,MAAME,qCAAqCN,MAAMG,qBAAqB,CACpE,0CACA;QACEC,aACE;IACJ;IAGFJ,MAAMO,0BAA0B,CAC9B,OAAOC;QACL,MAAM,CAACC,aAAaC,+BAA+B,GAAG,MAAMC,QAAQC,UAAU,CAAC;YAC7Ef;YACAC,kCAAkC;gBAChCe,cAAcjB,OAAOkB,iDAAiD;YACxE;SACD;QAED,IAAIL,YAAYM,MAAM,KAAK,aAAa;YACtCP,SAASQ,OAAO,CAACd,sBAAsBO,YAAYQ,KAAK,CAACf,oBAAoB;YAC7EM,SAASQ,OAAO,CAACX,sBAAsBI,YAAYQ,KAAK,CAACZ,oBAAoB;QAC/E;QACA,IAAIK,+BAA+BK,MAAM,KAAK,aAAa;YACzDP,SAASQ,OAAO,CAACV,oCAAoCI,+BAA+BO,KAAK;QAC3F;IACF,GACA;QAACf;QAAsBG;QAAsBC;KAAmC;AAEpF"}
1
+ {"version":3,"sources":["../../src/metrics/service.ts"],"sourcesContent":["import {getServiceMetricsProvider} from '@shipfox/node-opentelemetry';\nimport {config} from '#config.js';\nimport {getJobExecutionQueueDepth} from '#db/job-executions.js';\nimport {\n countStaleEnrolledRunnerInstances,\n listProviderRunnerByPhaseMetrics,\n type ProviderRunnerPhaseMetric,\n} from '#db/runner-instances.js';\n\ntype ProviderRunnerPhaseLabels = {\n phase: ProviderRunnerPhaseMetric['phase'];\n provider: string;\n launch_kind: ProviderRunnerPhaseMetric['launchKind'];\n};\n\nexport function registerRunnersServiceMetrics(): void {\n const meter = getServiceMetricsProvider().getMeter('runners');\n\n const pendingJobExecutions = meter.createObservableGauge('runners_pending_job_executions', {\n description: 'Job executions currently waiting in the queue to be claimed',\n });\n const runningJobExecutions = meter.createObservableGauge('runners_running_job_executions', {\n description: 'Job executions currently claimed by a runner and in progress',\n });\n const enrolledRunnersWithoutRecentReport = meter.createObservableGauge(\n 'runners_enrolled_without_recent_report',\n {\n description:\n 'Running enrolled runners with a live control session, no workspace or runner session, and no recent provisioner report after the stale-runner grace window',\n },\n );\n const providerRunnersByPhase = meter.createObservableGauge<ProviderRunnerPhaseLabels>(\n 'runners_provider_runner_by_phase',\n {\n description:\n 'Provider runners by lifecycle phase, including idle runners without an active assignment',\n },\n );\n const providerRunnersByPhaseOldestAge = meter.createObservableGauge<ProviderRunnerPhaseLabels>(\n 'runners_provider_runner_by_phase_oldest_age',\n {\n description: 'Oldest provider runner age by lifecycle phase',\n unit: 'ms',\n },\n );\n\n meter.addBatchObservableCallback(\n async (observer) => {\n const [depthResult, staleEnrolledRunnerCountResult, providerRunnersByPhaseResult] =\n await Promise.allSettled([\n getJobExecutionQueueDepth(),\n countStaleEnrolledRunnerInstances({\n graceSeconds: config.RUNNER_STALE_PROVISIONED_RUNNER_THRESHOLD_SECONDS,\n }),\n listProviderRunnerByPhaseMetrics(),\n ]);\n\n if (depthResult.status === 'fulfilled') {\n observer.observe(pendingJobExecutions, depthResult.value.pendingJobExecutions);\n observer.observe(runningJobExecutions, depthResult.value.runningJobExecutions);\n }\n if (staleEnrolledRunnerCountResult.status === 'fulfilled') {\n observer.observe(enrolledRunnersWithoutRecentReport, staleEnrolledRunnerCountResult.value);\n }\n if (providerRunnersByPhaseResult.status === 'fulfilled') {\n for (const metric of providerRunnersByPhaseResult.value) {\n const attributes: ProviderRunnerPhaseLabels = {\n phase: metric.phase,\n provider: metric.provider,\n launch_kind: metric.launchKind,\n };\n observer.observe(providerRunnersByPhase, metric.count, attributes);\n observer.observe(\n providerRunnersByPhaseOldestAge,\n metric.oldestAgeMilliseconds,\n attributes,\n );\n }\n }\n },\n [\n pendingJobExecutions,\n runningJobExecutions,\n enrolledRunnersWithoutRecentReport,\n providerRunnersByPhase,\n providerRunnersByPhaseOldestAge,\n ],\n );\n}\n"],"names":["getServiceMetricsProvider","config","getJobExecutionQueueDepth","countStaleEnrolledRunnerInstances","listProviderRunnerByPhaseMetrics","registerRunnersServiceMetrics","meter","getMeter","pendingJobExecutions","createObservableGauge","description","runningJobExecutions","enrolledRunnersWithoutRecentReport","providerRunnersByPhase","providerRunnersByPhaseOldestAge","unit","addBatchObservableCallback","observer","depthResult","staleEnrolledRunnerCountResult","providerRunnersByPhaseResult","Promise","allSettled","graceSeconds","RUNNER_STALE_PROVISIONED_RUNNER_THRESHOLD_SECONDS","status","observe","value","metric","attributes","phase","provider","launch_kind","launchKind","count","oldestAgeMilliseconds"],"mappings":"AAAA,SAAQA,yBAAyB,QAAO,8BAA8B;AACtE,SAAQC,MAAM,QAAO,aAAa;AAClC,SAAQC,yBAAyB,QAAO,wBAAwB;AAChE,SACEC,iCAAiC,EACjCC,gCAAgC,QAE3B,0BAA0B;AAQjC,OAAO,SAASC;IACd,MAAMC,QAAQN,4BAA4BO,QAAQ,CAAC;IAEnD,MAAMC,uBAAuBF,MAAMG,qBAAqB,CAAC,kCAAkC;QACzFC,aAAa;IACf;IACA,MAAMC,uBAAuBL,MAAMG,qBAAqB,CAAC,kCAAkC;QACzFC,aAAa;IACf;IACA,MAAME,qCAAqCN,MAAMG,qBAAqB,CACpE,0CACA;QACEC,aACE;IACJ;IAEF,MAAMG,yBAAyBP,MAAMG,qBAAqB,CACxD,oCACA;QACEC,aACE;IACJ;IAEF,MAAMI,kCAAkCR,MAAMG,qBAAqB,CACjE,+CACA;QACEC,aAAa;QACbK,MAAM;IACR;IAGFT,MAAMU,0BAA0B,CAC9B,OAAOC;QACL,MAAM,CAACC,aAAaC,gCAAgCC,6BAA6B,GAC/E,MAAMC,QAAQC,UAAU,CAAC;YACvBpB;YACAC,kCAAkC;gBAChCoB,cAActB,OAAOuB,iDAAiD;YACxE;YACApB;SACD;QAEH,IAAIc,YAAYO,MAAM,KAAK,aAAa;YACtCR,SAASS,OAAO,CAAClB,sBAAsBU,YAAYS,KAAK,CAACnB,oBAAoB;YAC7ES,SAASS,OAAO,CAACf,sBAAsBO,YAAYS,KAAK,CAAChB,oBAAoB;QAC/E;QACA,IAAIQ,+BAA+BM,MAAM,KAAK,aAAa;YACzDR,SAASS,OAAO,CAACd,oCAAoCO,+BAA+BQ,KAAK;QAC3F;QACA,IAAIP,6BAA6BK,MAAM,KAAK,aAAa;YACvD,KAAK,MAAMG,UAAUR,6BAA6BO,KAAK,CAAE;gBACvD,MAAME,aAAwC;oBAC5CC,OAAOF,OAAOE,KAAK;oBACnBC,UAAUH,OAAOG,QAAQ;oBACzBC,aAAaJ,OAAOK,UAAU;gBAChC;gBACAhB,SAASS,OAAO,CAACb,wBAAwBe,OAAOM,KAAK,EAAEL;gBACvDZ,SAASS,OAAO,CACdZ,iCACAc,OAAOO,qBAAqB,EAC5BN;YAEJ;QACF;IACF,GACA;QACErB;QACAG;QACAC;QACAC;QACAC;KACD;AAEL"}
@@ -1 +1 @@
1
- {"version":3,"file":"poll-demand.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/poll-demand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAEtD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,qBAAqB,CAkBvF"}
1
+ {"version":3,"file":"poll-demand.d.ts","sourceRoot":"","sources":["../../../src/presentation/dto/poll-demand.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,iBAAiB,CAAC;AAEtD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,qBAAqB,CAqBvF"}