@shipfox/api-runners 5.0.0 → 6.0.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 (414) hide show
  1. package/.turbo/turbo-build.log +6 -6
  2. package/CHANGELOG.md +61 -0
  3. package/dist/config.d.ts +5 -1
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/config.js +53 -6
  6. package/dist/config.js.map +1 -1
  7. package/dist/core/capacity-assignments.d.ts +7 -0
  8. package/dist/core/capacity-assignments.d.ts.map +1 -0
  9. package/dist/core/capacity-assignments.js +6 -0
  10. package/dist/core/capacity-assignments.js.map +1 -0
  11. package/dist/core/demand.d.ts +6 -6
  12. package/dist/core/demand.d.ts.map +1 -1
  13. package/dist/core/demand.js +10 -10
  14. package/dist/core/demand.js.map +1 -1
  15. package/dist/core/entities/capacity-assignment.d.ts +9 -0
  16. package/dist/core/entities/capacity-assignment.d.ts.map +1 -0
  17. package/dist/core/entities/capacity-assignment.js +3 -0
  18. package/dist/core/entities/capacity-assignment.js.map +1 -0
  19. package/dist/core/entities/ephemeral-registration-token.d.ts +1 -1
  20. package/dist/core/entities/ephemeral-registration-token.d.ts.map +1 -1
  21. package/dist/core/entities/ephemeral-registration-token.js.map +1 -1
  22. package/dist/core/entities/provisioner-capability-snapshot.d.ts +13 -0
  23. package/dist/core/entities/provisioner-capability-snapshot.d.ts.map +1 -0
  24. package/dist/core/entities/provisioner-capability-snapshot.js +3 -0
  25. package/dist/core/entities/provisioner-capability-snapshot.js.map +1 -0
  26. package/dist/core/entities/provisioner-token.d.ts +10 -2
  27. package/dist/core/entities/provisioner-token.d.ts.map +1 -1
  28. package/dist/core/entities/provisioner-token.js.map +1 -1
  29. package/dist/core/entities/{provisioned-runner.d.ts → runner-instance.d.ts} +6 -6
  30. package/dist/core/entities/runner-instance.d.ts.map +1 -0
  31. package/dist/core/entities/runner-instance.js +3 -0
  32. package/dist/core/entities/runner-instance.js.map +1 -0
  33. package/dist/core/entities/runner-session.d.ts +4 -2
  34. package/dist/core/entities/runner-session.d.ts.map +1 -1
  35. package/dist/core/entities/runner-session.js.map +1 -1
  36. package/dist/core/ephemeral-registration-tokens.d.ts +5 -5
  37. package/dist/core/ephemeral-registration-tokens.d.ts.map +1 -1
  38. package/dist/core/ephemeral-registration-tokens.js +12 -12
  39. package/dist/core/ephemeral-registration-tokens.js.map +1 -1
  40. package/dist/core/errors.d.ts +16 -4
  41. package/dist/core/errors.d.ts.map +1 -1
  42. package/dist/core/errors.js +22 -4
  43. package/dist/core/errors.js.map +1 -1
  44. package/dist/core/index.d.ts +10 -4
  45. package/dist/core/index.d.ts.map +1 -1
  46. package/dist/core/index.js +6 -2
  47. package/dist/core/index.js.map +1 -1
  48. package/dist/core/job-executions.d.ts +2 -0
  49. package/dist/core/job-executions.d.ts.map +1 -1
  50. package/dist/core/job-executions.js +1 -2
  51. package/dist/core/job-executions.js.map +1 -1
  52. package/dist/core/maintenance.d.ts +1 -1
  53. package/dist/core/maintenance.d.ts.map +1 -1
  54. package/dist/core/maintenance.js +5 -5
  55. package/dist/core/maintenance.js.map +1 -1
  56. package/dist/core/provisioner-capability-snapshots.d.ts +5 -0
  57. package/dist/core/provisioner-capability-snapshots.d.ts.map +1 -0
  58. package/dist/core/provisioner-capability-snapshots.js +10 -0
  59. package/dist/core/provisioner-capability-snapshots.js.map +1 -0
  60. package/dist/core/provisioner-tokens.d.ts +10 -0
  61. package/dist/core/provisioner-tokens.d.ts.map +1 -1
  62. package/dist/core/provisioner-tokens.js +23 -1
  63. package/dist/core/provisioner-tokens.js.map +1 -1
  64. package/dist/core/rate-limit.d.ts.map +1 -1
  65. package/dist/core/rate-limit.js +2 -7
  66. package/dist/core/rate-limit.js.map +1 -1
  67. package/dist/core/runner-activation.d.ts +13 -0
  68. package/dist/core/runner-activation.d.ts.map +1 -0
  69. package/dist/core/runner-activation.js +36 -0
  70. package/dist/core/runner-activation.js.map +1 -0
  71. package/dist/core/runner-control-sessions.d.ts +46 -0
  72. package/dist/core/runner-control-sessions.d.ts.map +1 -0
  73. package/dist/core/runner-control-sessions.js +121 -0
  74. package/dist/core/runner-control-sessions.js.map +1 -0
  75. package/dist/core/runner-instances.d.ts +79 -0
  76. package/dist/core/runner-instances.d.ts.map +1 -0
  77. package/dist/core/runner-instances.js +168 -0
  78. package/dist/core/runner-instances.js.map +1 -0
  79. package/dist/core/runner-sessions.d.ts +8 -2
  80. package/dist/core/runner-sessions.d.ts.map +1 -1
  81. package/dist/core/runner-sessions.js +8 -5
  82. package/dist/core/runner-sessions.js.map +1 -1
  83. package/dist/db/capacity-assignments.d.ts +7 -0
  84. package/dist/db/capacity-assignments.d.ts.map +1 -0
  85. package/dist/db/capacity-assignments.js +72 -0
  86. package/dist/db/capacity-assignments.js.map +1 -0
  87. package/dist/db/db.d.ts +2837 -1009
  88. package/dist/db/db.d.ts.map +1 -1
  89. package/dist/db/db.js +11 -2
  90. package/dist/db/db.js.map +1 -1
  91. package/dist/db/ephemeral-registration-tokens.d.ts +2 -2
  92. package/dist/db/ephemeral-registration-tokens.d.ts.map +1 -1
  93. package/dist/db/ephemeral-registration-tokens.js +21 -21
  94. package/dist/db/ephemeral-registration-tokens.js.map +1 -1
  95. package/dist/db/index.d.ts +7 -4
  96. package/dist/db/index.d.ts.map +1 -1
  97. package/dist/db/index.js +5 -2
  98. package/dist/db/index.js.map +1 -1
  99. package/dist/db/job-executions.d.ts +6 -6
  100. package/dist/db/job-executions.d.ts.map +1 -1
  101. package/dist/db/job-executions.js +20 -19
  102. package/dist/db/job-executions.js.map +1 -1
  103. package/dist/db/provisioner-capability-snapshots.d.ts +21 -0
  104. package/dist/db/provisioner-capability-snapshots.d.ts.map +1 -0
  105. package/dist/db/provisioner-capability-snapshots.js +57 -0
  106. package/dist/db/provisioner-capability-snapshots.js.map +1 -0
  107. package/dist/db/provisioner-tokens.d.ts +7 -2
  108. package/dist/db/provisioner-tokens.d.ts.map +1 -1
  109. package/dist/db/provisioner-tokens.js +59 -10
  110. package/dist/db/provisioner-tokens.js.map +1 -1
  111. package/dist/db/reservations.d.ts +18 -0
  112. package/dist/db/reservations.d.ts.map +1 -1
  113. package/dist/db/reservations.js +88 -1
  114. package/dist/db/reservations.js.map +1 -1
  115. package/dist/db/runner-instances.d.ts +91 -0
  116. package/dist/db/runner-instances.d.ts.map +1 -0
  117. package/dist/db/runner-instances.js +511 -0
  118. package/dist/db/runner-instances.js.map +1 -0
  119. package/dist/db/runner-sessions.d.ts +5 -0
  120. package/dist/db/runner-sessions.d.ts.map +1 -1
  121. package/dist/db/runner-sessions.js +48 -2
  122. package/dist/db/runner-sessions.js.map +1 -1
  123. package/dist/db/schema/capacity-assignments.d.ts +113 -0
  124. package/dist/db/schema/capacity-assignments.d.ts.map +1 -0
  125. package/dist/db/schema/capacity-assignments.js +29 -0
  126. package/dist/db/schema/capacity-assignments.js.map +1 -0
  127. package/dist/db/schema/ephemeral-registration-tokens.d.ts +2 -2
  128. package/dist/db/schema/ephemeral-registration-tokens.js +3 -3
  129. package/dist/db/schema/ephemeral-registration-tokens.js.map +1 -1
  130. package/dist/db/schema/provisioner-capability-snapshots.d.ts +207 -0
  131. package/dist/db/schema/provisioner-capability-snapshots.d.ts.map +1 -0
  132. package/dist/db/schema/provisioner-capability-snapshots.js +38 -0
  133. package/dist/db/schema/provisioner-capability-snapshots.js.map +1 -0
  134. package/dist/db/schema/provisioner-tokens.d.ts +19 -1
  135. package/dist/db/schema/provisioner-tokens.d.ts.map +1 -1
  136. package/dist/db/schema/provisioner-tokens.js +29 -3
  137. package/dist/db/schema/provisioner-tokens.js.map +1 -1
  138. package/dist/db/schema/runner-activation-tokens.d.ts +161 -0
  139. package/dist/db/schema/runner-activation-tokens.d.ts.map +1 -0
  140. package/dist/db/schema/runner-activation-tokens.js +27 -0
  141. package/dist/db/schema/runner-activation-tokens.js.map +1 -0
  142. package/dist/db/schema/runner-control-sessions.d.ts +338 -0
  143. package/dist/db/schema/runner-control-sessions.d.ts.map +1 -0
  144. package/dist/db/schema/runner-control-sessions.js +52 -0
  145. package/dist/db/schema/runner-control-sessions.js.map +1 -0
  146. package/dist/db/schema/{provisioned-runners.d.ts → runner-instances.d.ts} +88 -34
  147. package/dist/db/schema/runner-instances.d.ts.map +1 -0
  148. package/dist/db/schema/{provisioned-runners.js → runner-instances.js} +19 -14
  149. package/dist/db/schema/runner-instances.js.map +1 -0
  150. package/dist/db/schema/runner-sessions.d.ts +39 -5
  151. package/dist/db/schema/runner-sessions.d.ts.map +1 -1
  152. package/dist/db/schema/runner-sessions.js +13 -6
  153. package/dist/db/schema/runner-sessions.js.map +1 -1
  154. package/dist/db/schema/running-job-executions.d.ts +2 -2
  155. package/dist/db/schema/running-job-executions.js +4 -4
  156. package/dist/db/schema/running-job-executions.js.map +1 -1
  157. package/dist/index.d.ts +7 -2
  158. package/dist/index.d.ts.map +1 -1
  159. package/dist/index.js +45 -38
  160. package/dist/index.js.map +1 -1
  161. package/dist/installation-provisioning.d.ts +14 -0
  162. package/dist/installation-provisioning.d.ts.map +1 -0
  163. package/dist/installation-provisioning.js +7 -0
  164. package/dist/installation-provisioning.js.map +1 -0
  165. package/dist/metrics/index.d.ts +1 -1
  166. package/dist/metrics/index.d.ts.map +1 -1
  167. package/dist/metrics/index.js +1 -1
  168. package/dist/metrics/index.js.map +1 -1
  169. package/dist/metrics/instance.d.ts +11 -7
  170. package/dist/metrics/instance.d.ts.map +1 -1
  171. package/dist/metrics/instance.js +13 -7
  172. package/dist/metrics/instance.js.map +1 -1
  173. package/dist/presentation/auth/index.d.ts +1 -0
  174. package/dist/presentation/auth/index.d.ts.map +1 -1
  175. package/dist/presentation/auth/index.js +1 -0
  176. package/dist/presentation/auth/index.js.map +1 -1
  177. package/dist/presentation/auth/provisioner-token-auth.d.ts.map +1 -1
  178. package/dist/presentation/auth/provisioner-token-auth.js +5 -1
  179. package/dist/presentation/auth/provisioner-token-auth.js.map +1 -1
  180. package/dist/presentation/auth/runner-control-session-auth.d.ts +4 -0
  181. package/dist/presentation/auth/runner-control-session-auth.d.ts.map +1 -0
  182. package/dist/presentation/auth/runner-control-session-auth.js +29 -0
  183. package/dist/presentation/auth/runner-control-session-auth.js.map +1 -0
  184. package/dist/presentation/auth/runner-registration-token-auth.d.ts +5 -1
  185. package/dist/presentation/auth/runner-registration-token-auth.d.ts.map +1 -1
  186. package/dist/presentation/auth/runner-registration-token-auth.js +21 -1
  187. package/dist/presentation/auth/runner-registration-token-auth.js.map +1 -1
  188. package/dist/presentation/dto/index.d.ts +2 -2
  189. package/dist/presentation/dto/index.d.ts.map +1 -1
  190. package/dist/presentation/dto/index.js +2 -2
  191. package/dist/presentation/dto/index.js.map +1 -1
  192. package/dist/presentation/dto/mint-registration-tokens.d.ts +5 -3
  193. package/dist/presentation/dto/mint-registration-tokens.d.ts.map +1 -1
  194. package/dist/presentation/dto/mint-registration-tokens.js +4 -4
  195. package/dist/presentation/dto/mint-registration-tokens.js.map +1 -1
  196. package/dist/presentation/dto/poll-demand.d.ts.map +1 -1
  197. package/dist/presentation/dto/poll-demand.js +7 -1
  198. package/dist/presentation/dto/poll-demand.js.map +1 -1
  199. package/dist/presentation/dto/provisioner-token.d.ts +1 -0
  200. package/dist/presentation/dto/provisioner-token.d.ts.map +1 -1
  201. package/dist/presentation/dto/provisioner-token.js +5 -1
  202. package/dist/presentation/dto/provisioner-token.js.map +1 -1
  203. package/dist/presentation/dto/{provisioned-runners.d.ts → runner-instances.d.ts} +9 -9
  204. package/dist/presentation/dto/runner-instances.d.ts.map +1 -0
  205. package/dist/presentation/dto/{provisioned-runners.js → runner-instances.js} +6 -6
  206. package/dist/presentation/dto/runner-instances.js.map +1 -0
  207. package/dist/presentation/index.d.ts +2 -2
  208. package/dist/presentation/index.d.ts.map +1 -1
  209. package/dist/presentation/index.js +2 -2
  210. package/dist/presentation/index.js.map +1 -1
  211. package/dist/presentation/inter-module.d.ts +5 -0
  212. package/dist/presentation/inter-module.d.ts.map +1 -0
  213. package/dist/presentation/inter-module.js +43 -0
  214. package/dist/presentation/inter-module.js.map +1 -0
  215. package/dist/presentation/routes/assign-capacity.d.ts +2 -0
  216. package/dist/presentation/routes/assign-capacity.d.ts.map +1 -0
  217. package/dist/presentation/routes/assign-capacity.js +44 -0
  218. package/dist/presentation/routes/assign-capacity.js.map +1 -0
  219. package/dist/presentation/routes/get-provisioner-me.d.ts.map +1 -1
  220. package/dist/presentation/routes/get-provisioner-me.js +5 -1
  221. package/dist/presentation/routes/get-provisioner-me.js.map +1 -1
  222. package/dist/presentation/routes/heartbeat.d.ts +2 -1
  223. package/dist/presentation/routes/heartbeat.d.ts.map +1 -1
  224. package/dist/presentation/routes/heartbeat.js +60 -50
  225. package/dist/presentation/routes/heartbeat.js.map +1 -1
  226. package/dist/presentation/routes/index.d.ts +3 -1
  227. package/dist/presentation/routes/index.d.ts.map +1 -1
  228. package/dist/presentation/routes/index.js +83 -50
  229. package/dist/presentation/routes/index.js.map +1 -1
  230. package/dist/presentation/routes/mint-registration-tokens.d.ts.map +1 -1
  231. package/dist/presentation/routes/mint-registration-tokens.js +5 -5
  232. package/dist/presentation/routes/mint-registration-tokens.js.map +1 -1
  233. package/dist/presentation/routes/planned-capacity.d.ts +3 -0
  234. package/dist/presentation/routes/planned-capacity.d.ts.map +1 -0
  235. package/dist/presentation/routes/planned-capacity.js +54 -0
  236. package/dist/presentation/routes/planned-capacity.js.map +1 -0
  237. package/dist/presentation/routes/poll-demand.d.ts +2 -0
  238. package/dist/presentation/routes/poll-demand.d.ts.map +1 -1
  239. package/dist/presentation/routes/poll-demand.js +86 -45
  240. package/dist/presentation/routes/poll-demand.js.map +1 -1
  241. package/dist/presentation/routes/reconcile-runner-instances.d.ts +2 -0
  242. package/dist/presentation/routes/reconcile-runner-instances.d.ts.map +1 -0
  243. package/dist/presentation/routes/reconcile-runner-instances.js +27 -0
  244. package/dist/presentation/routes/reconcile-runner-instances.js.map +1 -0
  245. package/dist/presentation/routes/register.d.ts +2 -1
  246. package/dist/presentation/routes/register.d.ts.map +1 -1
  247. package/dist/presentation/routes/register.js +55 -52
  248. package/dist/presentation/routes/register.js.map +1 -1
  249. package/dist/presentation/routes/report-runner-instances.d.ts +2 -0
  250. package/dist/presentation/routes/report-runner-instances.d.ts.map +1 -0
  251. package/dist/presentation/routes/report-runner-instances.js +37 -0
  252. package/dist/presentation/routes/report-runner-instances.js.map +1 -0
  253. package/dist/presentation/routes/request-job.d.ts +2 -1
  254. package/dist/presentation/routes/request-job.d.ts.map +1 -1
  255. package/dist/presentation/routes/request-job.js +39 -36
  256. package/dist/presentation/routes/request-job.js.map +1 -1
  257. package/dist/presentation/routes/runner-enrollment.d.ts +7 -0
  258. package/dist/presentation/routes/runner-enrollment.d.ts.map +1 -0
  259. package/dist/presentation/routes/runner-enrollment.js +185 -0
  260. package/dist/presentation/routes/runner-enrollment.js.map +1 -0
  261. package/dist/temporal/activities/index.d.ts +2 -2
  262. package/dist/temporal/activities/index.d.ts.map +1 -1
  263. package/dist/temporal/activities/index.js +2 -2
  264. package/dist/temporal/activities/index.js.map +1 -1
  265. package/dist/temporal/activities/maintenance-activities.d.ts +1 -1
  266. package/dist/temporal/activities/maintenance-activities.d.ts.map +1 -1
  267. package/dist/temporal/activities/maintenance-activities.js +3 -3
  268. package/dist/temporal/activities/maintenance-activities.js.map +1 -1
  269. package/dist/temporal/workflows/index.bundle.js +3 -3
  270. package/dist/temporal/workflows/stuck-job-detector.js +2 -2
  271. package/dist/temporal/workflows/stuck-job-detector.js.map +1 -1
  272. package/dist/tsconfig.test.tsbuildinfo +1 -1
  273. package/drizzle/0000_initial.sql +102 -24
  274. package/drizzle/meta/0000_snapshot.json +483 -63
  275. package/package.json +21 -16
  276. package/src/config.test.ts +0 -26
  277. package/src/config.ts +47 -6
  278. package/src/core/capacity-assignments.ts +10 -0
  279. package/src/core/demand.test.ts +29 -29
  280. package/src/core/demand.ts +22 -22
  281. package/src/core/entities/capacity-assignment.ts +8 -0
  282. package/src/core/entities/ephemeral-registration-token.ts +1 -1
  283. package/src/core/entities/provisioner-capability-snapshot.ts +12 -0
  284. package/src/core/entities/provisioner-token.ts +8 -2
  285. package/src/core/entities/{provisioned-runner.ts → runner-instance.ts} +5 -5
  286. package/src/core/entities/runner-session.ts +4 -2
  287. package/src/core/ephemeral-registration-tokens.test.ts +11 -11
  288. package/src/core/ephemeral-registration-tokens.ts +18 -20
  289. package/src/core/errors.ts +23 -4
  290. package/src/core/index.ts +39 -17
  291. package/src/core/job-executions.ts +3 -2
  292. package/src/core/maintenance.test.ts +13 -17
  293. package/src/core/maintenance.ts +5 -5
  294. package/src/core/provisioner-capability-snapshots.test.ts +35 -0
  295. package/src/core/provisioner-capability-snapshots.ts +12 -0
  296. package/src/core/provisioner-tokens.test.ts +20 -0
  297. package/src/core/provisioner-tokens.ts +33 -0
  298. package/src/core/rate-limit.test.ts +11 -27
  299. package/src/core/rate-limit.ts +3 -11
  300. package/src/core/runner-activation.ts +72 -0
  301. package/src/core/runner-control-sessions.ts +190 -0
  302. package/src/core/{provisioned-runners.test.ts → runner-instances.test.ts} +24 -24
  303. package/src/core/runner-instances.ts +310 -0
  304. package/src/core/runner-sessions.test.ts +112 -22
  305. package/src/core/runner-sessions.ts +25 -14
  306. package/src/db/capacity-assignments.test.ts +159 -0
  307. package/src/db/capacity-assignments.ts +116 -0
  308. package/src/db/db.ts +11 -2
  309. package/src/db/ephemeral-registration-tokens.test.ts +9 -9
  310. package/src/db/ephemeral-registration-tokens.ts +26 -26
  311. package/src/db/index.ts +31 -21
  312. package/src/db/job-executions.test.ts +13 -11
  313. package/src/db/job-executions.ts +33 -27
  314. package/src/db/provisioner-capability-snapshots.test.ts +175 -0
  315. package/src/db/provisioner-capability-snapshots.ts +130 -0
  316. package/src/db/provisioner-tokens.test.ts +139 -2
  317. package/src/db/provisioner-tokens.ts +123 -15
  318. package/src/db/reservations.test.ts +49 -0
  319. package/src/db/reservations.ts +146 -1
  320. package/src/db/{provisioned-runners.test.ts → runner-instances.test.ts} +429 -353
  321. package/src/db/runner-instances.ts +942 -0
  322. package/src/db/runner-sessions.test.ts +19 -6
  323. package/src/db/runner-sessions.ts +78 -2
  324. package/src/db/schema/capacity-assignments.ts +34 -0
  325. package/src/db/schema/ephemeral-registration-tokens.ts +4 -4
  326. package/src/db/schema/provisioner-capability-snapshots.ts +46 -0
  327. package/src/db/schema/provisioner-tokens.ts +33 -2
  328. package/src/db/schema/runner-activation-tokens.ts +22 -0
  329. package/src/db/schema/runner-control-sessions.ts +46 -0
  330. package/src/db/schema/{provisioned-runners.ts → runner-instances.ts} +26 -27
  331. package/src/db/schema/runner-sessions.ts +11 -7
  332. package/src/db/schema/running-job-executions.ts +5 -5
  333. package/src/index.test.ts +26 -0
  334. package/src/index.ts +39 -19
  335. package/src/installation-provisioning.ts +14 -0
  336. package/src/metrics/index.ts +5 -5
  337. package/src/metrics/instance.ts +25 -14
  338. package/src/presentation/auth/index.ts +4 -0
  339. package/src/presentation/auth/provisioner-token-auth.ts +8 -4
  340. package/src/presentation/auth/runner-control-session-auth.ts +31 -0
  341. package/src/presentation/auth/runner-registration-token-auth.ts +39 -3
  342. package/src/presentation/dto/index.ts +5 -5
  343. package/src/presentation/dto/mint-registration-tokens.ts +8 -15
  344. package/src/presentation/dto/poll-demand.ts +3 -1
  345. package/src/presentation/dto/provisioner-token.ts +5 -0
  346. package/src/presentation/dto/{provisioned-runners.ts → runner-instances.ts} +13 -15
  347. package/src/presentation/index.ts +2 -1
  348. package/src/presentation/inter-module.test.ts +15 -0
  349. package/src/presentation/inter-module.ts +53 -0
  350. package/src/presentation/routes/assign-capacity.ts +48 -0
  351. package/src/presentation/routes/get-provisioner-me.ts +3 -4
  352. package/src/presentation/routes/heartbeat.test.ts +4 -3
  353. package/src/presentation/routes/heartbeat.ts +67 -64
  354. package/src/presentation/routes/index.ts +93 -43
  355. package/src/presentation/routes/list-active-runners.test.ts +23 -23
  356. package/src/presentation/routes/manual-registration-tokens.test.ts +4 -3
  357. package/src/presentation/routes/mint-registration-tokens.test.ts +12 -12
  358. package/src/presentation/routes/mint-registration-tokens.ts +5 -7
  359. package/src/presentation/routes/planned-capacity.ts +49 -0
  360. package/src/presentation/routes/poll-demand-release.test.ts +4 -4
  361. package/src/presentation/routes/poll-demand.test.ts +161 -22
  362. package/src/presentation/routes/poll-demand.ts +105 -45
  363. package/src/presentation/routes/provisioner-me.test.ts +37 -3
  364. package/src/presentation/routes/{reconcile-provisioned-runners.test.ts → reconcile-runner-instances.test.ts} +66 -61
  365. package/src/presentation/routes/reconcile-runner-instances.ts +30 -0
  366. package/src/presentation/routes/register.test.ts +9 -5
  367. package/src/presentation/routes/register.ts +61 -57
  368. package/src/presentation/routes/{report-provisioned-runners.test.ts → report-runner-instances.test.ts} +28 -28
  369. package/src/presentation/routes/{report-provisioned-runners.ts → report-runner-instances.ts} +14 -14
  370. package/src/presentation/routes/request-job.test.ts +5 -3
  371. package/src/presentation/routes/request-job.ts +41 -37
  372. package/src/presentation/routes/runner-enrollment.test.ts +259 -0
  373. package/src/presentation/routes/runner-enrollment.ts +174 -0
  374. package/src/temporal/activities/index.ts +2 -2
  375. package/src/temporal/activities/maintenance-activities.test.ts +7 -7
  376. package/src/temporal/activities/maintenance-activities.ts +3 -3
  377. package/src/temporal/workflows/stuck-job-detector.test.ts +3 -3
  378. package/src/temporal/workflows/stuck-job-detector.ts +2 -2
  379. package/test/env.ts +1 -3
  380. package/test/factories/ephemeral-registration-token.ts +2 -2
  381. package/test/factories/provisioner-token.ts +3 -1
  382. package/test/factories/runner-instance.ts +57 -0
  383. package/test/factories/runner-session.ts +3 -1
  384. package/test/fixtures/auth-inter-module.ts +30 -0
  385. package/test/globalSetup.ts +5 -1
  386. package/test/index.ts +2 -1
  387. package/tsconfig.build.tsbuildinfo +1 -1
  388. package/dist/core/entities/provisioned-runner.d.ts.map +0 -1
  389. package/dist/core/entities/provisioned-runner.js +0 -3
  390. package/dist/core/entities/provisioned-runner.js.map +0 -1
  391. package/dist/core/provisioned-runners.d.ts +0 -67
  392. package/dist/core/provisioned-runners.d.ts.map +0 -1
  393. package/dist/core/provisioned-runners.js +0 -162
  394. package/dist/core/provisioned-runners.js.map +0 -1
  395. package/dist/db/provisioned-runners.d.ts +0 -79
  396. package/dist/db/provisioned-runners.d.ts.map +0 -1
  397. package/dist/db/provisioned-runners.js +0 -466
  398. package/dist/db/provisioned-runners.js.map +0 -1
  399. package/dist/db/schema/provisioned-runners.d.ts.map +0 -1
  400. package/dist/db/schema/provisioned-runners.js.map +0 -1
  401. package/dist/presentation/dto/provisioned-runners.d.ts.map +0 -1
  402. package/dist/presentation/dto/provisioned-runners.js.map +0 -1
  403. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts +0 -2
  404. package/dist/presentation/routes/reconcile-provisioned-runners.d.ts.map +0 -1
  405. package/dist/presentation/routes/reconcile-provisioned-runners.js +0 -27
  406. package/dist/presentation/routes/reconcile-provisioned-runners.js.map +0 -1
  407. package/dist/presentation/routes/report-provisioned-runners.d.ts +0 -2
  408. package/dist/presentation/routes/report-provisioned-runners.d.ts.map +0 -1
  409. package/dist/presentation/routes/report-provisioned-runners.js +0 -37
  410. package/dist/presentation/routes/report-provisioned-runners.js.map +0 -1
  411. package/src/core/provisioned-runners.ts +0 -301
  412. package/src/db/provisioned-runners.ts +0 -886
  413. package/src/presentation/routes/reconcile-provisioned-runners.ts +0 -30
  414. package/test/factories/provisioned-runner.ts +0 -78
@@ -0,0 +1,511 @@
1
+ import { logger } from '@shipfox/node-opentelemetry';
2
+ import { canonicalizeLabels } from '@shipfox/runner-labels';
3
+ import { and, asc, desc, eq, exists, gt, inArray, isNotNull, isNull, lt, notExists, notInArray, or, sql } from 'drizzle-orm';
4
+ import { alias } from 'drizzle-orm/pg-core';
5
+ import { db } from './db.js';
6
+ import { listRunningJobExecutionsByRunnerInstanceTx } from './job-executions.js';
7
+ import { releaseReservationUnits } from './reservations.js';
8
+ import { ephemeralRegistrationTokens } from './schema/ephemeral-registration-tokens.js';
9
+ import { provisionerTokens } from './schema/provisioner-tokens.js';
10
+ import { providerRunners, toRunnerInstance } from './schema/runner-instances.js';
11
+ import { runnerSessions } from './schema/runner-sessions.js';
12
+ import { runningJobExecutions } from './schema/running-job-executions.js';
13
+ export const terminalStates = [
14
+ 'stopped',
15
+ 'failed',
16
+ 'terminated'
17
+ ];
18
+ export const activeStates = [
19
+ 'starting',
20
+ 'running',
21
+ 'stopping'
22
+ ];
23
+ export const divergenceCountStates = [
24
+ 'starting',
25
+ 'running'
26
+ ];
27
+ export async function createPlannedProvisionedCapacity(params) {
28
+ const [row] = await db().insert(providerRunners).values({
29
+ provisionerId: params.provisionerId,
30
+ providerKind: params.providerKind,
31
+ templateKey: params.templateKey,
32
+ state: 'starting',
33
+ labels: [],
34
+ reportedAt: new Date()
35
+ }).returning({
36
+ capacityId: providerRunners.id
37
+ });
38
+ if (!row) throw new Error('Planned capacity insert returned no row');
39
+ return row;
40
+ }
41
+ export async function attachProviderRunnerId(params) {
42
+ const updated = await db().update(providerRunners).set({
43
+ providerRunnerId: params.providerRunnerId,
44
+ updatedAt: sql`now()`
45
+ }).where(and(eq(providerRunners.id, params.capacityId), eq(providerRunners.provisionerId, params.provisionerId), isNull(providerRunners.providerRunnerId), notInArray(providerRunners.state, [
46
+ ...terminalStates
47
+ ]))).returning({
48
+ id: providerRunners.id
49
+ });
50
+ return updated.length === 1;
51
+ }
52
+ export async function reportRunnerInstances(params) {
53
+ if (params.events.length === 0) return {
54
+ accepted: 0,
55
+ reservationsReleased: 0,
56
+ terminateIntentsHonored: []
57
+ };
58
+ return await db().transaction(async (tx)=>{
59
+ const receivedAt = new Date();
60
+ const aggregatedEvents = aggregateEvents(params.events, receivedAt);
61
+ const hasTerminalEvent = aggregatedEvents.some((event)=>isTerminalState(event.state));
62
+ if (hasTerminalEvent) {
63
+ await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`);
64
+ }
65
+ const events = await hydrateRunnerSessionIdsFromConsumedTokens(tx, params, aggregatedEvents);
66
+ const terminateIntentsHonored = await listTerminateIntentsHonoredByTerminatedReportsTx(tx, params, events);
67
+ const values = events.map((event)=>({
68
+ workspaceId: params.workspaceId,
69
+ provisionerId: params.provisionerId,
70
+ providerRunnerId: event.providerRunnerId,
71
+ reservationId: event.reservationId,
72
+ templateKey: event.templateKey,
73
+ labels: [
74
+ ...canonicalizeLabels(event.labels)
75
+ ],
76
+ state: event.state,
77
+ reason: event.reason,
78
+ runnerSessionId: event.runnerSessionId,
79
+ providerKind: event.providerKind,
80
+ reportedAt: event.reportedAt > receivedAt ? receivedAt : event.reportedAt,
81
+ startedAt: event.startedAt,
82
+ stoppingAt: event.stoppingAt,
83
+ stoppedAt: event.stoppedAt,
84
+ failedAt: event.failedAt,
85
+ terminatedAt: event.terminatedAt
86
+ }));
87
+ await tx.insert(providerRunners).values(values).onConflictDoUpdate({
88
+ target: [
89
+ providerRunners.provisionerId,
90
+ providerRunners.providerRunnerId
91
+ ],
92
+ targetWhere: isNotNull(providerRunners.providerRunnerId),
93
+ set: {
94
+ reservationId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.reservation_id, ${providerRunners.reservationId}) ELSE ${providerRunners.reservationId} END`,
95
+ templateKey: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.template_key, ${providerRunners.templateKey}) ELSE ${providerRunners.templateKey} END`,
96
+ labels: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.labels ELSE ${providerRunners.labels} END`,
97
+ state: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.state ELSE ${providerRunners.state} END`,
98
+ reason: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reason ELSE ${providerRunners.reason} END`,
99
+ runnerSessionId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(${providerRunners.runnerSessionId}, excluded.runner_session_id) ELSE ${providerRunners.runnerSessionId} END`,
100
+ providerKind: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.provider_kind, ${providerRunners.providerKind}) ELSE ${providerRunners.providerKind} END`,
101
+ reportedAt: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reported_at ELSE ${providerRunners.reportedAt} END`,
102
+ startedAt: firstObservedAt(providerRunners.startedAt, sql`excluded.started_at`),
103
+ stoppingAt: firstObservedAt(providerRunners.stoppingAt, sql`excluded.stopping_at`),
104
+ stoppedAt: firstObservedAt(providerRunners.stoppedAt, sql`excluded.stopped_at`),
105
+ failedAt: firstObservedAt(providerRunners.failedAt, sql`excluded.failed_at`),
106
+ terminatedAt: firstObservedAt(providerRunners.terminatedAt, sql`excluded.terminated_at`),
107
+ updatedAt: sql`now()`
108
+ },
109
+ setWhere: sql`
110
+ ${providerRunnerProjectionUpdateCondition()}
111
+ OR ${providerRunnerMilestoneUpdateCondition()}
112
+ `
113
+ });
114
+ const reservationsReleased = hasTerminalEvent ? await releaseTerminalRunnerInstanceReservations(tx, params, events) : 0;
115
+ return {
116
+ accepted: events.length,
117
+ reservationsReleased,
118
+ terminateIntentsHonored
119
+ };
120
+ });
121
+ }
122
+ export async function listActiveRunnerInstanceCountsByTemplateTx(tx, params) {
123
+ const rows = await tx.select({
124
+ templateKey: providerRunners.templateKey,
125
+ state: providerRunners.state,
126
+ count: sql`count(*)::int`
127
+ }).from(providerRunners).where(and(eq(providerRunners.workspaceId, params.workspaceId), eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.state, divergenceCountStates), isNotNull(providerRunners.templateKey))).groupBy(providerRunners.templateKey, providerRunners.state);
128
+ return rows.flatMap((row)=>row.templateKey && isDivergenceCountState(row.state) ? [
129
+ {
130
+ templateKey: row.templateKey,
131
+ state: row.state,
132
+ count: row.count
133
+ }
134
+ ] : []);
135
+ }
136
+ export async function listActiveRunnerInstances(params) {
137
+ const rows = await db().select().from(providerRunners).where(and(eq(providerRunners.workspaceId, params.workspaceId), inArray(providerRunners.state, activeStates), sql`${providerRunners.updatedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`)).orderBy(desc(providerRunners.updatedAt), desc(providerRunners.id)).limit(params.limit ?? 1000);
138
+ return rows.map(toRunnerInstance);
139
+ }
140
+ export async function listProvisionerTerminateIntents(params) {
141
+ return await db().transaction(async (tx)=>{
142
+ const rows = await listProvisionerTerminateIntentRowsTx(tx, params);
143
+ return rows.map((row)=>row.providerRunnerId);
144
+ });
145
+ }
146
+ export async function listProvisionerTerminateIntentRowsTx(tx, params) {
147
+ const rows = await provisionerTerminateIntentsQuery(tx, params).orderBy(asc(providerRunners.providerRunnerId)).limit(params.limit + 1);
148
+ const truncated = rows.length > params.limit;
149
+ const returnedRows = truncated ? rows.slice(0, params.limit) : rows;
150
+ if (truncated) {
151
+ logger().warn({
152
+ workspaceId: params.workspaceId,
153
+ provisionerId: params.provisionerId,
154
+ limit: params.limit,
155
+ returnedCount: returnedRows.length
156
+ }, 'provisioner terminate intents truncated by poll-demand limit');
157
+ }
158
+ return returnedRows.flatMap((row)=>row.providerRunnerId ? [
159
+ {
160
+ ...row,
161
+ providerRunnerId: row.providerRunnerId
162
+ }
163
+ ] : []);
164
+ }
165
+ function provisionerTerminateIntentsQuery(tx, params) {
166
+ const newerRunningJobExecutions = alias(runningJobExecutions, 'newer_running_jobs');
167
+ return tx.select({
168
+ providerRunnerId: providerRunners.providerRunnerId,
169
+ reason: sql`'job-cancelled'`
170
+ }).from(runningJobExecutions).innerJoin(providerRunners, and(eq(providerRunners.workspaceId, runningJobExecutions.workspaceId), eq(providerRunners.provisionerId, runningJobExecutions.provisionerId), eq(providerRunners.providerRunnerId, runningJobExecutions.providerRunnerId))).where(and(eq(runningJobExecutions.workspaceId, params.workspaceId), eq(runningJobExecutions.provisionerId, params.provisionerId), isNotNull(providerRunners.providerRunnerId), isNotNull(runningJobExecutions.cancellationRequestedAt), inArray(providerRunners.state, activeStates), params.providerRunnerIds && params.providerRunnerIds.length > 0 ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds) : undefined, notExists(tx.select({
171
+ id: newerRunningJobExecutions.id
172
+ }).from(newerRunningJobExecutions).where(and(eq(newerRunningJobExecutions.workspaceId, runningJobExecutions.workspaceId), eq(newerRunningJobExecutions.provisionerId, runningJobExecutions.provisionerId), eq(newerRunningJobExecutions.providerRunnerId, runningJobExecutions.providerRunnerId), or(gt(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt), and(eq(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt), gt(newerRunningJobExecutions.jobExecutionId, runningJobExecutions.jobExecutionId)))))))).groupBy(providerRunners.providerRunnerId);
173
+ }
174
+ async function listTerminateIntentsHonoredByTerminatedReportsTx(tx, params, events) {
175
+ if (!params.workspaceId) return [];
176
+ const terminatedRunnerInstanceIds = [
177
+ ...new Set(events.filter((event)=>event.state === 'terminated').map((event)=>event.providerRunnerId))
178
+ ];
179
+ if (terminatedRunnerInstanceIds.length === 0) return [];
180
+ const rows = await provisionerTerminateIntentsQuery(tx, {
181
+ workspaceId: params.workspaceId,
182
+ provisionerId: params.provisionerId,
183
+ providerRunnerIds: terminatedRunnerInstanceIds
184
+ }).orderBy(asc(providerRunners.providerRunnerId));
185
+ return rows.flatMap((row)=>row.providerRunnerId ? [
186
+ {
187
+ ...row,
188
+ providerRunnerId: row.providerRunnerId
189
+ }
190
+ ] : []);
191
+ }
192
+ export async function reconcileRunnerInstances(params) {
193
+ const observedRunnerInstanceIds = [
194
+ ...new Set(params.observedRunnerInstanceIds)
195
+ ];
196
+ return await db().transaction(async (tx)=>{
197
+ await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`);
198
+ let absentIds = [];
199
+ let reservationsReleased = 0;
200
+ if (observedRunnerInstanceIds.length > 0) {
201
+ const staleAbsentRows = await tx.select({
202
+ id: providerRunners.id,
203
+ providerRunnerId: providerRunners.providerRunnerId
204
+ }).from(providerRunners).where(and(params.workspaceId ? eq(providerRunners.workspaceId, params.workspaceId) : isNull(providerRunners.workspaceId), eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.state, activeStates), lt(providerRunners.reportedAt, sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`), notInArray(providerRunners.providerRunnerId, observedRunnerInstanceIds)));
205
+ if (staleAbsentRows.length > 0) {
206
+ const updated = await tx.update(providerRunners).set({
207
+ state: 'terminated',
208
+ terminatedAt: sql`coalesce(${providerRunners.terminatedAt}, now())`,
209
+ updatedAt: sql`now()`
210
+ }).where(and(inArray(providerRunners.id, staleAbsentRows.map((row)=>row.id)), inArray(providerRunners.state, activeStates), lt(providerRunners.reportedAt, sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`))).returning({
211
+ providerRunnerId: providerRunners.providerRunnerId
212
+ });
213
+ absentIds = updated.flatMap((row)=>row.providerRunnerId ? [
214
+ row.providerRunnerId
215
+ ] : []);
216
+ if (params.workspaceId) {
217
+ reservationsReleased = await releaseTerminalRunnerInstanceReservationsByIds(tx, {
218
+ workspaceId: params.workspaceId,
219
+ provisionerId: params.provisionerId,
220
+ providerRunnerIds: absentIds
221
+ });
222
+ }
223
+ }
224
+ }
225
+ const observedRows = observedRunnerInstanceIds.length === 0 ? [] : (await tx.select().from(providerRunners).where(and(params.workspaceId ? eq(providerRunners.workspaceId, params.workspaceId) : isNull(providerRunners.workspaceId), eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.providerRunnerId, observedRunnerInstanceIds)))).map(toRunnerInstance);
226
+ const boundJobExecutions = params.workspaceId ? await listRunningJobExecutionsByRunnerInstanceTx(tx, {
227
+ workspaceId: params.workspaceId,
228
+ provisionerId: params.provisionerId,
229
+ providerRunnerIds: observedRunnerInstanceIds
230
+ }) : [];
231
+ return {
232
+ observedRows,
233
+ boundJobExecutionsByRunnerInstanceId: new Map(boundJobExecutions.map((jobExecution)=>[
234
+ jobExecution.providerRunnerId,
235
+ jobExecution
236
+ ])),
237
+ absentIds,
238
+ reservationsReleased
239
+ };
240
+ });
241
+ }
242
+ export async function reapStaleRunnerInstances(params) {
243
+ const cutoff = staleRunnerInstanceCutoff(params.thresholdSeconds);
244
+ return await db().transaction(async (tx)=>{
245
+ const candidateRows = await tx.select({
246
+ id: providerRunners.id,
247
+ workspaceId: providerRunners.workspaceId,
248
+ provisionerId: providerRunners.provisionerId,
249
+ providerRunnerId: providerRunners.providerRunnerId
250
+ }).from(providerRunners).where(staleRunnerInstanceWhere(tx, cutoff)).orderBy(asc(providerRunners.updatedAt), asc(providerRunners.id)).limit(params.limit);
251
+ if (candidateRows.length === 0) return {
252
+ reaped: 0,
253
+ reservationsReleased: 0
254
+ };
255
+ const workspaceIds = [
256
+ ...new Set(candidateRows.flatMap((row)=>row.workspaceId ? [
257
+ row.workspaceId
258
+ ] : []))
259
+ ].sort();
260
+ for (const workspaceId of workspaceIds){
261
+ await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${workspaceId}))`);
262
+ }
263
+ const updatedRows = await tx.update(providerRunners).set({
264
+ state: 'failed',
265
+ reason: 'stale-provisioner',
266
+ failedAt: sql`coalesce(${providerRunners.failedAt}, now())`,
267
+ updatedAt: sql`now()`
268
+ }).where(and(inArray(providerRunners.id, candidateRows.map((row)=>row.id)), staleRunnerInstanceWhere(tx, cutoff))).returning({
269
+ workspaceId: providerRunners.workspaceId,
270
+ provisionerId: providerRunners.provisionerId,
271
+ providerRunnerId: providerRunners.providerRunnerId
272
+ });
273
+ let reservationsReleased = 0;
274
+ for (const group of groupRunnerInstanceIds(updatedRows)){
275
+ reservationsReleased += await releaseTerminalRunnerInstanceReservationsByIds(tx, {
276
+ workspaceId: group.workspaceId,
277
+ provisionerId: group.provisionerId,
278
+ providerRunnerIds: group.providerRunnerIds,
279
+ requireUnlinkedSession: false
280
+ });
281
+ }
282
+ return {
283
+ reaped: updatedRows.length,
284
+ reservationsReleased
285
+ };
286
+ });
287
+ }
288
+ async function releaseTerminalRunnerInstanceReservations(tx, params, events) {
289
+ const terminalEvents = events.filter((event)=>isTerminalState(event.state));
290
+ if (terminalEvents.length === 0 || !params.workspaceId) return 0;
291
+ return await releaseTerminalRunnerInstanceReservationsByIds(tx, {
292
+ workspaceId: params.workspaceId,
293
+ provisionerId: params.provisionerId,
294
+ providerRunnerIds: terminalEvents.map((event)=>event.providerRunnerId)
295
+ });
296
+ }
297
+ async function releaseTerminalRunnerInstanceReservationsByIds(tx, params) {
298
+ if (params.providerRunnerIds.length === 0) return 0;
299
+ const rows = await tx.select({
300
+ id: providerRunners.id,
301
+ reservationId: providerRunners.reservationId
302
+ }).from(providerRunners).where(and(eq(providerRunners.workspaceId, params.workspaceId), eq(providerRunners.provisionerId, params.provisionerId), inArray(providerRunners.providerRunnerId, params.providerRunnerIds), inArray(providerRunners.state, terminalStates), isNotNull(providerRunners.reservationId), params.requireUnlinkedSession === false ? undefined : isNull(providerRunners.runnerSessionId), isNull(providerRunners.reservationReleasedAt)));
303
+ if (rows.length === 0) return 0;
304
+ const updated = await tx.update(providerRunners).set({
305
+ reservationReleasedAt: sql`now()`,
306
+ updatedAt: sql`now()`
307
+ }).where(and(inArray(providerRunners.id, rows.map((row)=>row.id)), params.requireUnlinkedSession === false ? undefined : isNull(providerRunners.runnerSessionId), isNull(providerRunners.reservationReleasedAt))).returning({
308
+ reservationId: providerRunners.reservationId
309
+ });
310
+ const releasesByReservationId = new Map();
311
+ for (const row of updated){
312
+ if (!row.reservationId) continue;
313
+ releasesByReservationId.set(row.reservationId, (releasesByReservationId.get(row.reservationId) ?? 0) + 1);
314
+ }
315
+ if (releasesByReservationId.size === 0) return 0;
316
+ return await releaseReservationUnits(tx, {
317
+ workspaceId: params.workspaceId,
318
+ provisionerId: params.provisionerId,
319
+ releases: [
320
+ ...releasesByReservationId
321
+ ].map(([reservationId, count])=>({
322
+ reservationId,
323
+ count
324
+ }))
325
+ });
326
+ }
327
+ function staleRunnerInstanceCutoff(thresholdSeconds) {
328
+ return sql`now() - (${thresholdSeconds} || ' seconds')::interval`;
329
+ }
330
+ function staleRunnerInstanceWhere(tx, cutoff) {
331
+ return and(inArray(providerRunners.state, activeStates), lt(providerRunners.reportedAt, cutoff), lt(providerRunners.updatedAt, cutoff), exists(tx.select({
332
+ id: provisionerTokens.id
333
+ }).from(provisionerTokens).where(and(eq(provisionerTokens.id, providerRunners.provisionerId), or(isNull(provisionerTokens.lastSeenAt), lt(provisionerTokens.lastSeenAt, cutoff))))), notExists(tx.select({
334
+ id: runningJobExecutions.id
335
+ }).from(runningJobExecutions).where(and(eq(runningJobExecutions.workspaceId, providerRunners.workspaceId), eq(runningJobExecutions.provisionerId, providerRunners.provisionerId), eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId)))), notExists(tx.select({
336
+ id: runnerSessions.id
337
+ }).from(runnerSessions).where(and(eq(runnerSessions.workspaceId, providerRunners.workspaceId), eq(runnerSessions.provisionerId, providerRunners.provisionerId), eq(runnerSessions.providerRunnerId, providerRunners.providerRunnerId), sql`${runnerSessions.updatedAt} >= ${cutoff}`))));
338
+ }
339
+ function groupRunnerInstanceIds(rows) {
340
+ const groups = new Map();
341
+ for (const row of rows){
342
+ if (!row.workspaceId || !row.providerRunnerId) continue;
343
+ const key = `${row.workspaceId}:${row.provisionerId}`;
344
+ const group = groups.get(key) ?? {
345
+ workspaceId: row.workspaceId,
346
+ provisionerId: row.provisionerId,
347
+ providerRunnerIds: []
348
+ };
349
+ group.providerRunnerIds.push(row.providerRunnerId);
350
+ groups.set(key, group);
351
+ }
352
+ return [
353
+ ...groups.values()
354
+ ];
355
+ }
356
+ async function hydrateRunnerSessionIdsFromConsumedTokens(tx, params, events) {
357
+ if (!params.workspaceId) return events;
358
+ const providerRunnerIds = [
359
+ ...new Set(events.map((event)=>event.providerRunnerId))
360
+ ];
361
+ if (providerRunnerIds.length === 0) return events;
362
+ const tokenRows = await tx.select({
363
+ providerRunnerId: ephemeralRegistrationTokens.providerRunnerId,
364
+ consumedSessionId: ephemeralRegistrationTokens.consumedSessionId
365
+ }).from(ephemeralRegistrationTokens).where(and(eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId), eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId), inArray(ephemeralRegistrationTokens.providerRunnerId, providerRunnerIds), isNotNull(ephemeralRegistrationTokens.consumedSessionId))).orderBy(desc(ephemeralRegistrationTokens.consumedAt), desc(ephemeralRegistrationTokens.createdAt));
366
+ const consumedSessionIdsByRunnerInstanceId = new Map();
367
+ for (const row of tokenRows){
368
+ if (!row.consumedSessionId) continue;
369
+ if (consumedSessionIdsByRunnerInstanceId.has(row.providerRunnerId)) continue;
370
+ consumedSessionIdsByRunnerInstanceId.set(row.providerRunnerId, row.consumedSessionId);
371
+ }
372
+ if (consumedSessionIdsByRunnerInstanceId.size === 0) return events;
373
+ return events.map((event)=>{
374
+ const consumedSessionId = consumedSessionIdsByRunnerInstanceId.get(event.providerRunnerId);
375
+ if (!consumedSessionId || event.runnerSessionId === consumedSessionId) return event;
376
+ return {
377
+ ...event,
378
+ runnerSessionId: consumedSessionId
379
+ };
380
+ });
381
+ }
382
+ function aggregateEvents(events, receivedAt) {
383
+ const byRunnerInstanceId = new Map();
384
+ for (const rawEvent of events){
385
+ const event = toRunnerInstanceReportRow(rawEvent, receivedAt);
386
+ const existing = byRunnerInstanceId.get(event.providerRunnerId);
387
+ if (existing) mergeMilestones(existing, event);
388
+ if (!existing || compareRunnerInstanceReportEvents(event, existing) > 0) {
389
+ byRunnerInstanceId.set(event.providerRunnerId, existing ? mergeProjectionMetadata(event, existing) : event);
390
+ }
391
+ }
392
+ return [
393
+ ...byRunnerInstanceId.values()
394
+ ];
395
+ }
396
+ function toRunnerInstanceReportRow(event, receivedAt) {
397
+ const reportedAt = event.reportedAt > receivedAt ? receivedAt : event.reportedAt;
398
+ return {
399
+ ...event,
400
+ reportedAt,
401
+ startedAt: event.state === 'running' ? reportedAt : null,
402
+ stoppingAt: event.state === 'stopping' ? reportedAt : null,
403
+ stoppedAt: event.state === 'stopped' ? reportedAt : null,
404
+ failedAt: event.state === 'failed' ? reportedAt : null,
405
+ terminatedAt: event.state === 'terminated' ? reportedAt : null
406
+ };
407
+ }
408
+ function mergeMilestones(target, source) {
409
+ target.startedAt = earliestDate(target.startedAt, source.startedAt);
410
+ target.stoppingAt = earliestDate(target.stoppingAt, source.stoppingAt);
411
+ target.stoppedAt = earliestDate(target.stoppedAt, source.stoppedAt);
412
+ target.failedAt = earliestDate(target.failedAt, source.failedAt);
413
+ target.terminatedAt = earliestDate(target.terminatedAt, source.terminatedAt);
414
+ }
415
+ function mergeProjectionMetadata(event, existing) {
416
+ return {
417
+ ...event,
418
+ reservationId: event.reservationId ?? existing.reservationId,
419
+ templateKey: event.templateKey ?? existing.templateKey,
420
+ runnerSessionId: event.runnerSessionId ?? existing.runnerSessionId,
421
+ providerKind: event.providerKind ?? existing.providerKind,
422
+ ...pickMilestones(existing)
423
+ };
424
+ }
425
+ function pickMilestones(event) {
426
+ return {
427
+ startedAt: event.startedAt,
428
+ stoppingAt: event.stoppingAt,
429
+ stoppedAt: event.stoppedAt,
430
+ failedAt: event.failedAt,
431
+ terminatedAt: event.terminatedAt
432
+ };
433
+ }
434
+ function earliestDate(a, b) {
435
+ if (!a) return b;
436
+ if (!b) return a;
437
+ return a < b ? a : b;
438
+ }
439
+ function compareRunnerInstanceReportEvents(a, b) {
440
+ const timeDelta = a.reportedAt.getTime() - b.reportedAt.getTime();
441
+ const rankDelta = getRunnerInstanceStateRank(a.state) - getRunnerInstanceStateRank(b.state);
442
+ if (rankDelta !== 0) return rankDelta;
443
+ return timeDelta;
444
+ }
445
+ function getRunnerInstanceStateRank(state) {
446
+ switch(state){
447
+ case 'starting':
448
+ return 1;
449
+ case 'running':
450
+ return 2;
451
+ case 'stopping':
452
+ return 3;
453
+ case 'stopped':
454
+ return 4;
455
+ case 'failed':
456
+ return 5;
457
+ case 'terminated':
458
+ return 6;
459
+ }
460
+ }
461
+ function providerRunnerStateRank(state) {
462
+ return sql`
463
+ CASE ${state}
464
+ WHEN 'starting' THEN 1
465
+ WHEN 'running' THEN 2
466
+ WHEN 'stopping' THEN 3
467
+ WHEN 'stopped' THEN 4
468
+ WHEN 'failed' THEN 5
469
+ WHEN 'terminated' THEN 6
470
+ ELSE 0
471
+ END
472
+ `;
473
+ }
474
+ function providerRunnerProjectionUpdateCondition() {
475
+ return sql`
476
+ ${providerRunnerStateRank(sql`excluded.state`)} > ${providerRunnerStateRank(providerRunners.state)}
477
+ OR (
478
+ ${providerRunnerStateRank(sql`excluded.state`)} = ${providerRunnerStateRank(providerRunners.state)}
479
+ AND excluded.reported_at >= ${providerRunners.reportedAt}
480
+ )
481
+ `;
482
+ }
483
+ function providerRunnerMilestoneUpdateCondition() {
484
+ return sql`
485
+ ${milestoneNeedsUpdate(providerRunners.startedAt, sql`excluded.started_at`)}
486
+ OR ${milestoneNeedsUpdate(providerRunners.stoppingAt, sql`excluded.stopping_at`)}
487
+ OR ${milestoneNeedsUpdate(providerRunners.stoppedAt, sql`excluded.stopped_at`)}
488
+ OR ${milestoneNeedsUpdate(providerRunners.failedAt, sql`excluded.failed_at`)}
489
+ OR ${milestoneNeedsUpdate(providerRunners.terminatedAt, sql`excluded.terminated_at`)}
490
+ `;
491
+ }
492
+ function milestoneNeedsUpdate(current, incoming) {
493
+ return sql`${incoming} IS NOT NULL AND (${current} IS NULL OR ${incoming} < ${current})`;
494
+ }
495
+ function firstObservedAt(current, incoming) {
496
+ return sql`
497
+ CASE
498
+ WHEN ${incoming} IS NULL THEN ${current}
499
+ WHEN ${current} IS NULL THEN ${incoming}
500
+ ELSE least(${current}, ${incoming})
501
+ END
502
+ `;
503
+ }
504
+ export function isTerminalState(state) {
505
+ return terminalStates.includes(state);
506
+ }
507
+ function isDivergenceCountState(state) {
508
+ return divergenceCountStates.includes(state);
509
+ }
510
+
511
+ //# sourceMappingURL=runner-instances.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/db/runner-instances.ts"],"sourcesContent":["import {logger} from '@shipfox/node-opentelemetry';\nimport {canonicalizeLabels} from '@shipfox/runner-labels';\nimport {\n and,\n asc,\n desc,\n eq,\n exists,\n gt,\n inArray,\n isNotNull,\n isNull,\n lt,\n notExists,\n notInArray,\n or,\n type SQL,\n sql,\n} from 'drizzle-orm';\nimport {alias} from 'drizzle-orm/pg-core';\nimport type {RunnerInstance, RunnerInstanceState} from '#core/entities/runner-instance.js';\nimport type {Tx} from './db.js';\nimport {db} from './db.js';\nimport {\n listRunningJobExecutionsByRunnerInstanceTx,\n type RunnerInstanceBoundJobExecution,\n} from './job-executions.js';\nimport {releaseReservationUnits} from './reservations.js';\nimport {ephemeralRegistrationTokens} from './schema/ephemeral-registration-tokens.js';\nimport {provisionerTokens} from './schema/provisioner-tokens.js';\nimport {providerRunners, toRunnerInstance} from './schema/runner-instances.js';\nimport {runnerSessions} from './schema/runner-sessions.js';\nimport {runningJobExecutions} from './schema/running-job-executions.js';\n\nexport const terminalStates = [\n 'stopped',\n 'failed',\n 'terminated',\n] as const satisfies readonly RunnerInstanceState[];\nexport const activeStates = [\n 'starting',\n 'running',\n 'stopping',\n] as const satisfies readonly RunnerInstanceState[];\nexport const divergenceCountStates = ['starting', 'running'] as const satisfies readonly Extract<\n RunnerInstanceState,\n 'starting' | 'running'\n>[];\n\nexport type RunnerInstanceTerminateIntentReason = 'job-cancelled';\n\nexport interface RunnerInstanceTerminateIntent {\n providerRunnerId: string;\n reason: RunnerInstanceTerminateIntentReason;\n}\n\nexport interface ActiveRunnerInstanceTemplateCount {\n templateKey: string;\n state: (typeof divergenceCountStates)[number];\n count: number;\n}\n\nexport interface RunnerInstanceReportEvent {\n providerRunnerId: string;\n reservationId: string | null;\n templateKey: string | null;\n labels: string[];\n state: RunnerInstanceState;\n reason: string | null;\n runnerSessionId: string | null;\n providerKind: string | null;\n reportedAt: Date;\n}\n\nexport interface ReportRunnerInstancesParams {\n workspaceId: string | null;\n provisionerId: string;\n events: RunnerInstanceReportEvent[];\n}\n\nexport interface ReconcileRunnerInstancesParams {\n workspaceId: string | null;\n provisionerId: string;\n observedRunnerInstanceIds: string[];\n terminateGraceSeconds: number;\n}\n\nexport interface ReconcileRunnerInstancesDbResult {\n observedRows: RunnerInstance[];\n boundJobExecutionsByRunnerInstanceId: Map<string, RunnerInstanceBoundJobExecution>;\n absentIds: string[];\n reservationsReleased: number;\n}\n\nexport interface ReapStaleRunnerInstancesResult {\n reaped: number;\n reservationsReleased: number;\n}\n\nexport async function createPlannedProvisionedCapacity(params: {\n provisionerId: string;\n providerKind: string | null;\n templateKey: string | null;\n}): Promise<{capacityId: string}> {\n const [row] = await db()\n .insert(providerRunners)\n .values({\n provisionerId: params.provisionerId,\n providerKind: params.providerKind,\n templateKey: params.templateKey,\n state: 'starting',\n labels: [],\n reportedAt: new Date(),\n })\n .returning({capacityId: providerRunners.id});\n if (!row) throw new Error('Planned capacity insert returned no row');\n return row;\n}\n\nexport async function attachProviderRunnerId(params: {\n capacityId: string;\n provisionerId: string;\n providerRunnerId: string;\n}): Promise<boolean> {\n const updated = await db()\n .update(providerRunners)\n .set({providerRunnerId: params.providerRunnerId, updatedAt: sql`now()`})\n .where(\n and(\n eq(providerRunners.id, params.capacityId),\n eq(providerRunners.provisionerId, params.provisionerId),\n isNull(providerRunners.providerRunnerId),\n notInArray(providerRunners.state, [...terminalStates]),\n ),\n )\n .returning({id: providerRunners.id});\n return updated.length === 1;\n}\n\ninterface RunnerInstanceReportRow extends RunnerInstanceReportEvent {\n startedAt: Date | null;\n stoppingAt: Date | null;\n stoppedAt: Date | null;\n failedAt: Date | null;\n terminatedAt: Date | null;\n}\n\ntype RunnerInstanceMilestoneColumn =\n | typeof providerRunners.startedAt\n | typeof providerRunners.stoppingAt\n | typeof providerRunners.stoppedAt\n | typeof providerRunners.failedAt\n | typeof providerRunners.terminatedAt;\n\nexport async function reportRunnerInstances(params: ReportRunnerInstancesParams): Promise<{\n accepted: number;\n reservationsReleased: number;\n terminateIntentsHonored: RunnerInstanceTerminateIntent[];\n}> {\n if (params.events.length === 0)\n return {accepted: 0, reservationsReleased: 0, terminateIntentsHonored: []};\n\n return await db().transaction(async (tx) => {\n const receivedAt = new Date();\n const aggregatedEvents = aggregateEvents(params.events, receivedAt);\n const hasTerminalEvent = aggregatedEvents.some((event) => isTerminalState(event.state));\n\n if (hasTerminalEvent) {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`,\n );\n }\n\n const events = await hydrateRunnerSessionIdsFromConsumedTokens(tx, params, aggregatedEvents);\n const terminateIntentsHonored = await listTerminateIntentsHonoredByTerminatedReportsTx(\n tx,\n params,\n events,\n );\n\n const values = events.map((event) => ({\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerId: event.providerRunnerId,\n reservationId: event.reservationId,\n templateKey: event.templateKey,\n labels: [...canonicalizeLabels(event.labels)],\n state: event.state,\n reason: event.reason,\n runnerSessionId: event.runnerSessionId,\n providerKind: event.providerKind,\n reportedAt: event.reportedAt > receivedAt ? receivedAt : event.reportedAt,\n startedAt: event.startedAt,\n stoppingAt: event.stoppingAt,\n stoppedAt: event.stoppedAt,\n failedAt: event.failedAt,\n terminatedAt: event.terminatedAt,\n }));\n\n await tx\n .insert(providerRunners)\n .values(values)\n .onConflictDoUpdate({\n target: [providerRunners.provisionerId, providerRunners.providerRunnerId],\n targetWhere: isNotNull(providerRunners.providerRunnerId),\n set: {\n reservationId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.reservation_id, ${providerRunners.reservationId}) ELSE ${providerRunners.reservationId} END`,\n templateKey: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.template_key, ${providerRunners.templateKey}) ELSE ${providerRunners.templateKey} END`,\n labels: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.labels ELSE ${providerRunners.labels} END`,\n state: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.state ELSE ${providerRunners.state} END`,\n reason: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reason ELSE ${providerRunners.reason} END`,\n runnerSessionId: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(${providerRunners.runnerSessionId}, excluded.runner_session_id) ELSE ${providerRunners.runnerSessionId} END`,\n providerKind: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN coalesce(excluded.provider_kind, ${providerRunners.providerKind}) ELSE ${providerRunners.providerKind} END`,\n reportedAt: sql`CASE WHEN ${providerRunnerProjectionUpdateCondition()} THEN excluded.reported_at ELSE ${providerRunners.reportedAt} END`,\n startedAt: firstObservedAt(providerRunners.startedAt, sql`excluded.started_at`),\n stoppingAt: firstObservedAt(providerRunners.stoppingAt, sql`excluded.stopping_at`),\n stoppedAt: firstObservedAt(providerRunners.stoppedAt, sql`excluded.stopped_at`),\n failedAt: firstObservedAt(providerRunners.failedAt, sql`excluded.failed_at`),\n terminatedAt: firstObservedAt(providerRunners.terminatedAt, sql`excluded.terminated_at`),\n updatedAt: sql`now()`,\n },\n setWhere: sql`\n ${providerRunnerProjectionUpdateCondition()}\n OR ${providerRunnerMilestoneUpdateCondition()}\n `,\n });\n\n const reservationsReleased = hasTerminalEvent\n ? await releaseTerminalRunnerInstanceReservations(tx, params, events)\n : 0;\n\n return {accepted: events.length, reservationsReleased, terminateIntentsHonored};\n });\n}\n\nexport async function listActiveRunnerInstanceCountsByTemplateTx(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string},\n): Promise<ActiveRunnerInstanceTemplateCount[]> {\n const rows = await tx\n .select({\n templateKey: providerRunners.templateKey,\n state: providerRunners.state,\n count: sql<number>`count(*)::int`,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.state, divergenceCountStates),\n isNotNull(providerRunners.templateKey),\n ),\n )\n .groupBy(providerRunners.templateKey, providerRunners.state);\n\n return rows.flatMap((row) =>\n row.templateKey && isDivergenceCountState(row.state)\n ? [{templateKey: row.templateKey, state: row.state, count: row.count}]\n : [],\n );\n}\n\nexport async function listActiveRunnerInstances(params: {\n workspaceId: string;\n windowSeconds: number;\n limit?: number;\n}): Promise<RunnerInstance[]> {\n const rows = await db()\n .select()\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n inArray(providerRunners.state, activeStates),\n sql`${providerRunners.updatedAt} > now() - (${params.windowSeconds} || ' seconds')::interval`,\n ),\n )\n .orderBy(desc(providerRunners.updatedAt), desc(providerRunners.id))\n .limit(params.limit ?? 1000);\n\n return rows.map(toRunnerInstance);\n}\n\nexport async function listProvisionerTerminateIntents(params: {\n workspaceId: string;\n provisionerId: string;\n limit: number;\n}): Promise<string[]> {\n return await db().transaction(async (tx) => {\n const rows = await listProvisionerTerminateIntentRowsTx(tx, params);\n return rows.map((row) => row.providerRunnerId);\n });\n}\n\nexport async function listProvisionerTerminateIntentRowsTx(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n limit: number;\n },\n): Promise<RunnerInstanceTerminateIntent[]> {\n const rows = await provisionerTerminateIntentsQuery(tx, params)\n .orderBy(asc(providerRunners.providerRunnerId))\n .limit(params.limit + 1);\n\n const truncated = rows.length > params.limit;\n const returnedRows = truncated ? rows.slice(0, params.limit) : rows;\n if (truncated) {\n logger().warn(\n {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n limit: params.limit,\n returnedCount: returnedRows.length,\n },\n 'provisioner terminate intents truncated by poll-demand limit',\n );\n }\n\n return returnedRows.flatMap((row) =>\n row.providerRunnerId ? [{...row, providerRunnerId: row.providerRunnerId}] : [],\n );\n}\n\nfunction provisionerTerminateIntentsQuery(\n tx: Tx,\n params: {workspaceId: string; provisionerId: string; providerRunnerIds?: string[]},\n) {\n const newerRunningJobExecutions = alias(runningJobExecutions, 'newer_running_jobs');\n\n return tx\n .select({\n providerRunnerId: providerRunners.providerRunnerId,\n reason: sql<RunnerInstanceTerminateIntentReason>`'job-cancelled'`,\n })\n .from(runningJobExecutions)\n .innerJoin(\n providerRunners,\n and(\n eq(providerRunners.workspaceId, runningJobExecutions.workspaceId),\n eq(providerRunners.provisionerId, runningJobExecutions.provisionerId),\n eq(providerRunners.providerRunnerId, runningJobExecutions.providerRunnerId),\n ),\n )\n .where(\n and(\n eq(runningJobExecutions.workspaceId, params.workspaceId),\n eq(runningJobExecutions.provisionerId, params.provisionerId),\n isNotNull(providerRunners.providerRunnerId),\n isNotNull(runningJobExecutions.cancellationRequestedAt),\n inArray(providerRunners.state, activeStates),\n params.providerRunnerIds && params.providerRunnerIds.length > 0\n ? inArray(providerRunners.providerRunnerId, params.providerRunnerIds)\n : undefined,\n notExists(\n tx\n .select({id: newerRunningJobExecutions.id})\n .from(newerRunningJobExecutions)\n .where(\n and(\n eq(newerRunningJobExecutions.workspaceId, runningJobExecutions.workspaceId),\n eq(newerRunningJobExecutions.provisionerId, runningJobExecutions.provisionerId),\n eq(\n newerRunningJobExecutions.providerRunnerId,\n runningJobExecutions.providerRunnerId,\n ),\n or(\n gt(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt),\n and(\n eq(newerRunningJobExecutions.startedAt, runningJobExecutions.startedAt),\n gt(\n newerRunningJobExecutions.jobExecutionId,\n runningJobExecutions.jobExecutionId,\n ),\n ),\n ),\n ),\n ),\n ),\n ),\n )\n .groupBy(providerRunners.providerRunnerId);\n}\n\nasync function listTerminateIntentsHonoredByTerminatedReportsTx(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportEvent[],\n): Promise<RunnerInstanceTerminateIntent[]> {\n if (!params.workspaceId) return [];\n const terminatedRunnerInstanceIds = [\n ...new Set(\n events.filter((event) => event.state === 'terminated').map((event) => event.providerRunnerId),\n ),\n ];\n if (terminatedRunnerInstanceIds.length === 0) return [];\n\n const rows = await provisionerTerminateIntentsQuery(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: terminatedRunnerInstanceIds,\n }).orderBy(asc(providerRunners.providerRunnerId));\n return rows.flatMap((row) =>\n row.providerRunnerId ? [{...row, providerRunnerId: row.providerRunnerId}] : [],\n );\n}\n\nexport async function reconcileRunnerInstances(\n params: ReconcileRunnerInstancesParams,\n): Promise<ReconcileRunnerInstancesDbResult> {\n const observedRunnerInstanceIds = [...new Set(params.observedRunnerInstanceIds)];\n\n return await db().transaction(async (tx) => {\n await tx.execute(\n sql`select pg_advisory_xact_lock(hashtext(${params.workspaceId ?? params.provisionerId}))`,\n );\n\n let absentIds: string[] = [];\n let reservationsReleased = 0;\n if (observedRunnerInstanceIds.length > 0) {\n const staleAbsentRows = await tx\n .select({\n id: providerRunners.id,\n providerRunnerId: providerRunners.providerRunnerId,\n })\n .from(providerRunners)\n .where(\n and(\n params.workspaceId\n ? eq(providerRunners.workspaceId, params.workspaceId)\n : isNull(providerRunners.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.state, activeStates),\n lt(\n providerRunners.reportedAt,\n sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`,\n ),\n notInArray(providerRunners.providerRunnerId, observedRunnerInstanceIds),\n ),\n );\n\n if (staleAbsentRows.length > 0) {\n const updated = await tx\n .update(providerRunners)\n .set({\n state: 'terminated',\n terminatedAt: sql`coalesce(${providerRunners.terminatedAt}, now())`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n staleAbsentRows.map((row) => row.id),\n ),\n inArray(providerRunners.state, activeStates),\n lt(\n providerRunners.reportedAt,\n sql`now() - (${params.terminateGraceSeconds} || ' seconds')::interval`,\n ),\n ),\n )\n .returning({providerRunnerId: providerRunners.providerRunnerId});\n\n absentIds = updated.flatMap((row) => (row.providerRunnerId ? [row.providerRunnerId] : []));\n if (params.workspaceId) {\n reservationsReleased = await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: absentIds,\n });\n }\n }\n }\n\n const observedRows =\n observedRunnerInstanceIds.length === 0\n ? []\n : (\n await tx\n .select()\n .from(providerRunners)\n .where(\n and(\n params.workspaceId\n ? eq(providerRunners.workspaceId, params.workspaceId)\n : isNull(providerRunners.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, observedRunnerInstanceIds),\n ),\n )\n ).map(toRunnerInstance);\n\n const boundJobExecutions = params.workspaceId\n ? await listRunningJobExecutionsByRunnerInstanceTx(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: observedRunnerInstanceIds,\n })\n : [];\n\n return {\n observedRows,\n boundJobExecutionsByRunnerInstanceId: new Map(\n boundJobExecutions.map((jobExecution) => [jobExecution.providerRunnerId, jobExecution]),\n ),\n absentIds,\n reservationsReleased,\n };\n });\n}\n\nexport async function reapStaleRunnerInstances(params: {\n thresholdSeconds: number;\n limit: number;\n}): Promise<ReapStaleRunnerInstancesResult> {\n const cutoff = staleRunnerInstanceCutoff(params.thresholdSeconds);\n\n return await db().transaction(async (tx) => {\n const candidateRows = await tx\n .select({\n id: providerRunners.id,\n workspaceId: providerRunners.workspaceId,\n provisionerId: providerRunners.provisionerId,\n providerRunnerId: providerRunners.providerRunnerId,\n })\n .from(providerRunners)\n .where(staleRunnerInstanceWhere(tx, cutoff))\n .orderBy(asc(providerRunners.updatedAt), asc(providerRunners.id))\n .limit(params.limit);\n\n if (candidateRows.length === 0) return {reaped: 0, reservationsReleased: 0};\n\n const workspaceIds = [\n ...new Set(candidateRows.flatMap((row) => (row.workspaceId ? [row.workspaceId] : []))),\n ].sort();\n for (const workspaceId of workspaceIds) {\n await tx.execute(sql`select pg_advisory_xact_lock(hashtext(${workspaceId}))`);\n }\n\n const updatedRows = await tx\n .update(providerRunners)\n .set({\n state: 'failed',\n reason: 'stale-provisioner',\n failedAt: sql`coalesce(${providerRunners.failedAt}, now())`,\n updatedAt: sql`now()`,\n })\n .where(\n and(\n inArray(\n providerRunners.id,\n candidateRows.map((row) => row.id),\n ),\n staleRunnerInstanceWhere(tx, cutoff),\n ),\n )\n .returning({\n workspaceId: providerRunners.workspaceId,\n provisionerId: providerRunners.provisionerId,\n providerRunnerId: providerRunners.providerRunnerId,\n });\n\n let reservationsReleased = 0;\n for (const group of groupRunnerInstanceIds(updatedRows)) {\n reservationsReleased += await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: group.workspaceId,\n provisionerId: group.provisionerId,\n providerRunnerIds: group.providerRunnerIds,\n requireUnlinkedSession: false,\n });\n }\n\n return {reaped: updatedRows.length, reservationsReleased};\n });\n}\n\nasync function releaseTerminalRunnerInstanceReservations(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportEvent[],\n): Promise<number> {\n const terminalEvents = events.filter((event) => isTerminalState(event.state));\n if (terminalEvents.length === 0 || !params.workspaceId) return 0;\n\n return await releaseTerminalRunnerInstanceReservationsByIds(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n providerRunnerIds: terminalEvents.map((event) => event.providerRunnerId),\n });\n}\n\nasync function releaseTerminalRunnerInstanceReservationsByIds(\n tx: Tx,\n params: {\n workspaceId: string;\n provisionerId: string;\n providerRunnerIds: string[];\n requireUnlinkedSession?: boolean;\n },\n): Promise<number> {\n if (params.providerRunnerIds.length === 0) return 0;\n\n const rows = await tx\n .select({\n id: providerRunners.id,\n reservationId: providerRunners.reservationId,\n })\n .from(providerRunners)\n .where(\n and(\n eq(providerRunners.workspaceId, params.workspaceId),\n eq(providerRunners.provisionerId, params.provisionerId),\n inArray(providerRunners.providerRunnerId, params.providerRunnerIds),\n inArray(providerRunners.state, terminalStates),\n isNotNull(providerRunners.reservationId),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n );\n\n if (rows.length === 0) return 0;\n\n const updated = await tx\n .update(providerRunners)\n .set({reservationReleasedAt: sql`now()`, updatedAt: sql`now()`})\n .where(\n and(\n inArray(\n providerRunners.id,\n rows.map((row) => row.id),\n ),\n params.requireUnlinkedSession === false\n ? undefined\n : isNull(providerRunners.runnerSessionId),\n isNull(providerRunners.reservationReleasedAt),\n ),\n )\n .returning({reservationId: providerRunners.reservationId});\n\n const releasesByReservationId = new Map<string, number>();\n for (const row of updated) {\n if (!row.reservationId) continue;\n releasesByReservationId.set(\n row.reservationId,\n (releasesByReservationId.get(row.reservationId) ?? 0) + 1,\n );\n }\n\n if (releasesByReservationId.size === 0) return 0;\n\n return await releaseReservationUnits(tx, {\n workspaceId: params.workspaceId,\n provisionerId: params.provisionerId,\n releases: [...releasesByReservationId].map(([reservationId, count]) => ({\n reservationId,\n count,\n })),\n });\n}\n\nfunction staleRunnerInstanceCutoff(thresholdSeconds: number): SQL {\n return sql`now() - (${thresholdSeconds} || ' seconds')::interval`;\n}\n\nfunction staleRunnerInstanceWhere(tx: Tx, cutoff: SQL): SQL<boolean> {\n return and(\n inArray(providerRunners.state, activeStates),\n lt(providerRunners.reportedAt, cutoff),\n lt(providerRunners.updatedAt, cutoff),\n exists(\n tx\n .select({id: provisionerTokens.id})\n .from(provisionerTokens)\n .where(\n and(\n eq(provisionerTokens.id, providerRunners.provisionerId),\n or(isNull(provisionerTokens.lastSeenAt), lt(provisionerTokens.lastSeenAt, cutoff)),\n ),\n ),\n ),\n notExists(\n tx\n .select({id: runningJobExecutions.id})\n .from(runningJobExecutions)\n .where(\n and(\n eq(runningJobExecutions.workspaceId, providerRunners.workspaceId),\n eq(runningJobExecutions.provisionerId, providerRunners.provisionerId),\n eq(runningJobExecutions.providerRunnerId, providerRunners.providerRunnerId),\n ),\n ),\n ),\n notExists(\n tx\n .select({id: runnerSessions.id})\n .from(runnerSessions)\n .where(\n and(\n eq(runnerSessions.workspaceId, providerRunners.workspaceId),\n eq(runnerSessions.provisionerId, providerRunners.provisionerId),\n eq(runnerSessions.providerRunnerId, providerRunners.providerRunnerId),\n sql`${runnerSessions.updatedAt} >= ${cutoff}`,\n ),\n ),\n ),\n ) as SQL<boolean>;\n}\n\nfunction groupRunnerInstanceIds(\n rows: Array<{\n workspaceId: string | null;\n provisionerId: string;\n providerRunnerId: string | null;\n }>,\n): Array<{workspaceId: string; provisionerId: string; providerRunnerIds: string[]}> {\n const groups = new Map<\n string,\n {workspaceId: string; provisionerId: string; providerRunnerIds: string[]}\n >();\n for (const row of rows) {\n if (!row.workspaceId || !row.providerRunnerId) continue;\n const key = `${row.workspaceId}:${row.provisionerId}`;\n const group = groups.get(key) ?? {\n workspaceId: row.workspaceId,\n provisionerId: row.provisionerId,\n providerRunnerIds: [],\n };\n group.providerRunnerIds.push(row.providerRunnerId);\n groups.set(key, group);\n }\n return [...groups.values()];\n}\n\nasync function hydrateRunnerSessionIdsFromConsumedTokens(\n tx: Tx,\n params: ReportRunnerInstancesParams,\n events: RunnerInstanceReportRow[],\n): Promise<RunnerInstanceReportRow[]> {\n if (!params.workspaceId) return events;\n const providerRunnerIds = [...new Set(events.map((event) => event.providerRunnerId))];\n if (providerRunnerIds.length === 0) return events;\n\n const tokenRows = await tx\n .select({\n providerRunnerId: ephemeralRegistrationTokens.providerRunnerId,\n consumedSessionId: ephemeralRegistrationTokens.consumedSessionId,\n })\n .from(ephemeralRegistrationTokens)\n .where(\n and(\n eq(ephemeralRegistrationTokens.workspaceId, params.workspaceId),\n eq(ephemeralRegistrationTokens.provisionerId, params.provisionerId),\n inArray(ephemeralRegistrationTokens.providerRunnerId, providerRunnerIds),\n isNotNull(ephemeralRegistrationTokens.consumedSessionId),\n ),\n )\n .orderBy(\n desc(ephemeralRegistrationTokens.consumedAt),\n desc(ephemeralRegistrationTokens.createdAt),\n );\n\n const consumedSessionIdsByRunnerInstanceId = new Map<string, string>();\n for (const row of tokenRows) {\n if (!row.consumedSessionId) continue;\n if (consumedSessionIdsByRunnerInstanceId.has(row.providerRunnerId)) continue;\n consumedSessionIdsByRunnerInstanceId.set(row.providerRunnerId, row.consumedSessionId);\n }\n\n if (consumedSessionIdsByRunnerInstanceId.size === 0) return events;\n\n return events.map((event) => {\n const consumedSessionId = consumedSessionIdsByRunnerInstanceId.get(event.providerRunnerId);\n if (!consumedSessionId || event.runnerSessionId === consumedSessionId) return event;\n return {...event, runnerSessionId: consumedSessionId};\n });\n}\n\nfunction aggregateEvents(\n events: RunnerInstanceReportEvent[],\n receivedAt: Date,\n): RunnerInstanceReportRow[] {\n const byRunnerInstanceId = new Map<string, RunnerInstanceReportRow>();\n for (const rawEvent of events) {\n const event = toRunnerInstanceReportRow(rawEvent, receivedAt);\n const existing = byRunnerInstanceId.get(event.providerRunnerId);\n if (existing) mergeMilestones(existing, event);\n if (!existing || compareRunnerInstanceReportEvents(event, existing) > 0) {\n byRunnerInstanceId.set(\n event.providerRunnerId,\n existing ? mergeProjectionMetadata(event, existing) : event,\n );\n }\n }\n return [...byRunnerInstanceId.values()];\n}\n\nfunction toRunnerInstanceReportRow(\n event: RunnerInstanceReportEvent,\n receivedAt: Date,\n): RunnerInstanceReportRow {\n const reportedAt = event.reportedAt > receivedAt ? receivedAt : event.reportedAt;\n return {\n ...event,\n reportedAt,\n startedAt: event.state === 'running' ? reportedAt : null,\n stoppingAt: event.state === 'stopping' ? reportedAt : null,\n stoppedAt: event.state === 'stopped' ? reportedAt : null,\n failedAt: event.state === 'failed' ? reportedAt : null,\n terminatedAt: event.state === 'terminated' ? reportedAt : null,\n };\n}\n\nfunction mergeMilestones(target: RunnerInstanceReportRow, source: RunnerInstanceReportRow) {\n target.startedAt = earliestDate(target.startedAt, source.startedAt);\n target.stoppingAt = earliestDate(target.stoppingAt, source.stoppingAt);\n target.stoppedAt = earliestDate(target.stoppedAt, source.stoppedAt);\n target.failedAt = earliestDate(target.failedAt, source.failedAt);\n target.terminatedAt = earliestDate(target.terminatedAt, source.terminatedAt);\n}\n\nfunction mergeProjectionMetadata(\n event: RunnerInstanceReportRow,\n existing: RunnerInstanceReportRow,\n): RunnerInstanceReportRow {\n return {\n ...event,\n reservationId: event.reservationId ?? existing.reservationId,\n templateKey: event.templateKey ?? existing.templateKey,\n runnerSessionId: event.runnerSessionId ?? existing.runnerSessionId,\n providerKind: event.providerKind ?? existing.providerKind,\n ...pickMilestones(existing),\n };\n}\n\nfunction pickMilestones(event: RunnerInstanceReportRow) {\n return {\n startedAt: event.startedAt,\n stoppingAt: event.stoppingAt,\n stoppedAt: event.stoppedAt,\n failedAt: event.failedAt,\n terminatedAt: event.terminatedAt,\n };\n}\n\nfunction earliestDate(a: Date | null, b: Date | null): Date | null {\n if (!a) return b;\n if (!b) return a;\n return a < b ? a : b;\n}\n\nfunction compareRunnerInstanceReportEvents(\n a: RunnerInstanceReportEvent,\n b: RunnerInstanceReportEvent,\n): number {\n const timeDelta = a.reportedAt.getTime() - b.reportedAt.getTime();\n const rankDelta = getRunnerInstanceStateRank(a.state) - getRunnerInstanceStateRank(b.state);\n if (rankDelta !== 0) return rankDelta;\n return timeDelta;\n}\n\nfunction getRunnerInstanceStateRank(state: RunnerInstanceState): number {\n switch (state) {\n case 'starting':\n return 1;\n case 'running':\n return 2;\n case 'stopping':\n return 3;\n case 'stopped':\n return 4;\n case 'failed':\n return 5;\n case 'terminated':\n return 6;\n }\n}\n\nfunction providerRunnerStateRank(state: SQL | typeof providerRunners.state): SQL<number> {\n return sql<number>`\n CASE ${state}\n WHEN 'starting' THEN 1\n WHEN 'running' THEN 2\n WHEN 'stopping' THEN 3\n WHEN 'stopped' THEN 4\n WHEN 'failed' THEN 5\n WHEN 'terminated' THEN 6\n ELSE 0\n END\n `;\n}\n\nfunction providerRunnerProjectionUpdateCondition(): SQL<boolean> {\n return sql<boolean>`\n ${providerRunnerStateRank(sql`excluded.state`)} > ${providerRunnerStateRank(providerRunners.state)}\n OR (\n ${providerRunnerStateRank(sql`excluded.state`)} = ${providerRunnerStateRank(providerRunners.state)}\n AND excluded.reported_at >= ${providerRunners.reportedAt}\n )\n `;\n}\n\nfunction providerRunnerMilestoneUpdateCondition(): SQL<boolean> {\n return sql<boolean>`\n ${milestoneNeedsUpdate(providerRunners.startedAt, sql`excluded.started_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.stoppingAt, sql`excluded.stopping_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.stoppedAt, sql`excluded.stopped_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.failedAt, sql`excluded.failed_at`)}\n OR ${milestoneNeedsUpdate(providerRunners.terminatedAt, sql`excluded.terminated_at`)}\n `;\n}\n\nfunction milestoneNeedsUpdate(\n current: SQL | RunnerInstanceMilestoneColumn,\n incoming: SQL,\n): SQL<boolean> {\n return sql<boolean>`${incoming} IS NOT NULL AND (${current} IS NULL OR ${incoming} < ${current})`;\n}\n\nfunction firstObservedAt(current: SQL | RunnerInstanceMilestoneColumn, incoming: SQL) {\n return sql`\n CASE\n WHEN ${incoming} IS NULL THEN ${current}\n WHEN ${current} IS NULL THEN ${incoming}\n ELSE least(${current}, ${incoming})\n END\n `;\n}\n\nexport function isTerminalState(state: RunnerInstanceState): boolean {\n return terminalStates.includes(state as (typeof terminalStates)[number]);\n}\n\nfunction isDivergenceCountState(\n state: RunnerInstanceState,\n): state is (typeof divergenceCountStates)[number] {\n return divergenceCountStates.includes(state as (typeof divergenceCountStates)[number]);\n}\n"],"names":["logger","canonicalizeLabels","and","asc","desc","eq","exists","gt","inArray","isNotNull","isNull","lt","notExists","notInArray","or","sql","alias","db","listRunningJobExecutionsByRunnerInstanceTx","releaseReservationUnits","ephemeralRegistrationTokens","provisionerTokens","providerRunners","toRunnerInstance","runnerSessions","runningJobExecutions","terminalStates","activeStates","divergenceCountStates","createPlannedProvisionedCapacity","params","row","insert","values","provisionerId","providerKind","templateKey","state","labels","reportedAt","Date","returning","capacityId","id","Error","attachProviderRunnerId","updated","update","set","providerRunnerId","updatedAt","where","length","reportRunnerInstances","events","accepted","reservationsReleased","terminateIntentsHonored","transaction","tx","receivedAt","aggregatedEvents","aggregateEvents","hasTerminalEvent","some","event","isTerminalState","execute","workspaceId","hydrateRunnerSessionIdsFromConsumedTokens","listTerminateIntentsHonoredByTerminatedReportsTx","map","reservationId","reason","runnerSessionId","startedAt","stoppingAt","stoppedAt","failedAt","terminatedAt","onConflictDoUpdate","target","targetWhere","providerRunnerProjectionUpdateCondition","firstObservedAt","setWhere","providerRunnerMilestoneUpdateCondition","releaseTerminalRunnerInstanceReservations","listActiveRunnerInstanceCountsByTemplateTx","rows","select","count","from","groupBy","flatMap","isDivergenceCountState","listActiveRunnerInstances","windowSeconds","orderBy","limit","listProvisionerTerminateIntents","listProvisionerTerminateIntentRowsTx","provisionerTerminateIntentsQuery","truncated","returnedRows","slice","warn","returnedCount","newerRunningJobExecutions","innerJoin","cancellationRequestedAt","providerRunnerIds","undefined","jobExecutionId","terminatedRunnerInstanceIds","Set","filter","reconcileRunnerInstances","observedRunnerInstanceIds","absentIds","staleAbsentRows","terminateGraceSeconds","releaseTerminalRunnerInstanceReservationsByIds","observedRows","boundJobExecutions","boundJobExecutionsByRunnerInstanceId","Map","jobExecution","reapStaleRunnerInstances","cutoff","staleRunnerInstanceCutoff","thresholdSeconds","candidateRows","staleRunnerInstanceWhere","reaped","workspaceIds","sort","updatedRows","group","groupRunnerInstanceIds","requireUnlinkedSession","terminalEvents","reservationReleasedAt","releasesByReservationId","get","size","releases","lastSeenAt","groups","key","push","tokenRows","consumedSessionId","consumedAt","createdAt","consumedSessionIdsByRunnerInstanceId","has","byRunnerInstanceId","rawEvent","toRunnerInstanceReportRow","existing","mergeMilestones","compareRunnerInstanceReportEvents","mergeProjectionMetadata","source","earliestDate","pickMilestones","a","b","timeDelta","getTime","rankDelta","getRunnerInstanceStateRank","providerRunnerStateRank","milestoneNeedsUpdate","current","incoming","includes"],"mappings":"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"}
@@ -9,6 +9,11 @@ export interface CreateRunnerSessionParams {
9
9
  }
10
10
  export declare function createRunnerSession(params: CreateRunnerSessionParams): Promise<RunnerSession>;
11
11
  export declare function getRunnerSessionById(runnerSessionId: string): Promise<RunnerSession | null>;
12
+ export declare function createRunnerSessionConsumingActivationToken(params: {
13
+ activationTokenId: string;
14
+ labels: string[];
15
+ toolCapabilities?: RunnerToolCapabilitiesDto | null;
16
+ }): Promise<RunnerSession>;
12
17
  export interface DeleteExpiredRunnerSessionsParams {
13
18
  manualRetentionDays: number;
14
19
  ephemeralRetentionDays: number;