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