@shipfox/api-workflows 11.0.0 → 12.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 (346) hide show
  1. package/.turbo/turbo-build.log +8 -8
  2. package/CHANGELOG.md +100 -0
  3. package/README.md +75 -0
  4. package/dist/core/agent-defaults.d.ts +2 -1
  5. package/dist/core/agent-defaults.d.ts.map +1 -1
  6. package/dist/core/agent-defaults.js.map +1 -1
  7. package/dist/core/checkout.d.ts +7 -21
  8. package/dist/core/checkout.d.ts.map +1 -1
  9. package/dist/core/checkout.js +122 -41
  10. package/dist/core/checkout.js.map +1 -1
  11. package/dist/core/entities/job-execution.d.ts +8 -0
  12. package/dist/core/entities/job-execution.d.ts.map +1 -1
  13. package/dist/core/entities/job-execution.js +13 -1
  14. package/dist/core/entities/job-execution.js.map +1 -1
  15. package/dist/core/entities/job-listener-event.d.ts +2 -0
  16. package/dist/core/entities/job-listener-event.d.ts.map +1 -1
  17. package/dist/core/entities/job-listener-event.js.map +1 -1
  18. package/dist/core/entities/step.d.ts +13 -3
  19. package/dist/core/entities/step.d.ts.map +1 -1
  20. package/dist/core/entities/step.js +6 -0
  21. package/dist/core/entities/step.js.map +1 -1
  22. package/dist/core/entities/workflow-run-attempt.d.ts +1 -0
  23. package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
  24. package/dist/core/entities/workflow-run-attempt.js.map +1 -1
  25. package/dist/core/entities/workflow-run.d.ts +17 -0
  26. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  27. package/dist/core/entities/workflow-run.js.map +1 -1
  28. package/dist/core/errors.d.ts +9 -2
  29. package/dist/core/errors.d.ts.map +1 -1
  30. package/dist/core/errors.js +10 -5
  31. package/dist/core/errors.js.map +1 -1
  32. package/dist/core/job-execution.d.ts.map +1 -1
  33. package/dist/core/job-execution.js +14 -8
  34. package/dist/core/job-execution.js.map +1 -1
  35. package/dist/core/job-transition/decide-job-activation.d.ts +1 -0
  36. package/dist/core/job-transition/decide-job-activation.d.ts.map +1 -1
  37. package/dist/core/job-transition/decide-job-activation.js +1 -0
  38. package/dist/core/job-transition/decide-job-activation.js.map +1 -1
  39. package/dist/core/job-transition/derive-job-success.d.ts +1 -0
  40. package/dist/core/job-transition/derive-job-success.d.ts.map +1 -1
  41. package/dist/core/job-transition/derive-job-success.js +5 -8
  42. package/dist/core/job-transition/derive-job-success.js.map +1 -1
  43. package/dist/core/listener-execution-materialization.d.ts +6 -3
  44. package/dist/core/listener-execution-materialization.d.ts.map +1 -1
  45. package/dist/core/listener-execution-materialization.js +44 -6
  46. package/dist/core/listener-execution-materialization.js.map +1 -1
  47. package/dist/core/resolve-trigger-reference.d.ts +11 -0
  48. package/dist/core/resolve-trigger-reference.d.ts.map +1 -0
  49. package/dist/core/resolve-trigger-reference.js +39 -0
  50. package/dist/core/resolve-trigger-reference.js.map +1 -0
  51. package/dist/core/run-workflow.d.ts +1 -0
  52. package/dist/core/run-workflow.d.ts.map +1 -1
  53. package/dist/core/run-workflow.js +1 -0
  54. package/dist/core/run-workflow.js.map +1 -1
  55. package/dist/core/step-config/agent.d.ts +1 -2
  56. package/dist/core/step-config/agent.d.ts.map +1 -1
  57. package/dist/core/step-config/agent.js +22 -7
  58. package/dist/core/step-config/agent.js.map +1 -1
  59. package/dist/core/step-config/assemble-run-context.d.ts +19 -8
  60. package/dist/core/step-config/assemble-run-context.d.ts.map +1 -1
  61. package/dist/core/step-config/assemble-run-context.js +51 -19
  62. package/dist/core/step-config/assemble-run-context.js.map +1 -1
  63. package/dist/core/step-config/complete-step-dispatch-config.d.ts.map +1 -1
  64. package/dist/core/step-config/complete-step-dispatch-config.js +72 -4
  65. package/dist/core/step-config/complete-step-dispatch-config.js.map +1 -1
  66. package/dist/core/step-config/index.d.ts +1 -0
  67. package/dist/core/step-config/index.d.ts.map +1 -1
  68. package/dist/core/step-config/index.js +1 -0
  69. package/dist/core/step-config/index.js.map +1 -1
  70. package/dist/core/step-config/materialize-job-execution-steps.d.ts +1 -1
  71. package/dist/core/step-config/materialize-job-execution-steps.d.ts.map +1 -1
  72. package/dist/core/step-config/materialize-job-execution-steps.js +49 -8
  73. package/dist/core/step-config/materialize-job-execution-steps.js.map +1 -1
  74. package/dist/core/step-config/materialize-workflow-model.d.ts +3 -3
  75. package/dist/core/step-config/materialize-workflow-model.d.ts.map +1 -1
  76. package/dist/core/step-config/materialize-workflow-model.js +9 -5
  77. package/dist/core/step-config/materialize-workflow-model.js.map +1 -1
  78. package/dist/core/step-config/resolve-job-execution-name.d.ts +3 -3
  79. package/dist/core/step-config/resolve-job-execution-name.d.ts.map +1 -1
  80. package/dist/core/step-config/resolve-job-execution-name.js +24 -13
  81. package/dist/core/step-config/resolve-job-execution-name.js.map +1 -1
  82. package/dist/core/step-config/resolve-step-config.d.ts.map +1 -1
  83. package/dist/core/step-config/resolve-step-config.js +174 -9
  84. package/dist/core/step-config/resolve-step-config.js.map +1 -1
  85. package/dist/core/step-config/resolve-workflow-run-name.d.ts +19 -0
  86. package/dist/core/step-config/resolve-workflow-run-name.d.ts.map +1 -0
  87. package/dist/core/step-config/resolve-workflow-run-name.js +73 -0
  88. package/dist/core/step-config/resolve-workflow-run-name.js.map +1 -0
  89. package/dist/core/step-transition/decide-step-transition.js.map +1 -1
  90. package/dist/core/step-transition/evaluate-gate.d.ts +2 -1
  91. package/dist/core/step-transition/evaluate-gate.d.ts.map +1 -1
  92. package/dist/core/step-transition/evaluate-gate.js +5 -3
  93. package/dist/core/step-transition/evaluate-gate.js.map +1 -1
  94. package/dist/core/workflow-run-creation.d.ts +3 -0
  95. package/dist/core/workflow-run-creation.d.ts.map +1 -1
  96. package/dist/core/workflow-run-creation.js +22 -7
  97. package/dist/core/workflow-run-creation.js.map +1 -1
  98. package/dist/db/db.d.ts +278 -10
  99. package/dist/db/db.d.ts.map +1 -1
  100. package/dist/db/db.js +2 -0
  101. package/dist/db/db.js.map +1 -1
  102. package/dist/db/index.d.ts +3 -2
  103. package/dist/db/index.d.ts.map +1 -1
  104. package/dist/db/index.js +2 -1
  105. package/dist/db/index.js.map +1 -1
  106. package/dist/db/job-listener-events.d.ts +2 -0
  107. package/dist/db/job-listener-events.d.ts.map +1 -1
  108. package/dist/db/job-listener-events.js +1 -0
  109. package/dist/db/job-listener-events.js.map +1 -1
  110. package/dist/db/job-listeners.d.ts +2 -0
  111. package/dist/db/job-listeners.d.ts.map +1 -1
  112. package/dist/db/job-listeners.js +81 -21
  113. package/dist/db/job-listeners.js.map +1 -1
  114. package/dist/db/schema/job-executions.d.ts +3 -3
  115. package/dist/db/schema/job-executions.d.ts.map +1 -1
  116. package/dist/db/schema/job-executions.js +8 -4
  117. package/dist/db/schema/job-executions.js.map +1 -1
  118. package/dist/db/schema/job-listener-events.d.ts +20 -0
  119. package/dist/db/schema/job-listener-events.d.ts.map +1 -1
  120. package/dist/db/schema/job-listener-events.js +2 -0
  121. package/dist/db/schema/job-listener-events.js.map +1 -1
  122. package/dist/db/schema/step-attempts.js +2 -2
  123. package/dist/db/schema/step-attempts.js.map +1 -1
  124. package/dist/db/schema/steps.d.ts +4 -2
  125. package/dist/db/schema/steps.d.ts.map +1 -1
  126. package/dist/db/schema/steps.js +1 -1
  127. package/dist/db/schema/steps.js.map +1 -1
  128. package/dist/db/schema/workflow-run-attempts.d.ts +21 -2
  129. package/dist/db/schema/workflow-run-attempts.d.ts.map +1 -1
  130. package/dist/db/schema/workflow-run-attempts.js +2 -0
  131. package/dist/db/schema/workflow-run-attempts.js.map +1 -1
  132. package/dist/db/schema/workflow-run-counters.d.ts +43 -0
  133. package/dist/db/schema/workflow-run-counters.d.ts.map +1 -0
  134. package/dist/db/schema/workflow-run-counters.js +10 -0
  135. package/dist/db/schema/workflow-run-counters.js.map +1 -0
  136. package/dist/db/schema/workflow-runs.d.ts +54 -1
  137. package/dist/db/schema/workflow-runs.d.ts.map +1 -1
  138. package/dist/db/schema/workflow-runs.js +10 -2
  139. package/dist/db/schema/workflow-runs.js.map +1 -1
  140. package/dist/db/workflow-runs/job-executions.d.ts.map +1 -1
  141. package/dist/db/workflow-runs/job-executions.js +35 -14
  142. package/dist/db/workflow-runs/job-executions.js.map +1 -1
  143. package/dist/db/workflow-runs/jobs.d.ts +2 -0
  144. package/dist/db/workflow-runs/jobs.d.ts.map +1 -1
  145. package/dist/db/workflow-runs/jobs.js +9 -5
  146. package/dist/db/workflow-runs/jobs.js.map +1 -1
  147. package/dist/db/workflow-runs/queries.d.ts +51 -0
  148. package/dist/db/workflow-runs/queries.d.ts.map +1 -1
  149. package/dist/db/workflow-runs/queries.js +82 -2
  150. package/dist/db/workflow-runs/queries.js.map +1 -1
  151. package/dist/db/workflow-runs/run-create.d.ts +1 -0
  152. package/dist/db/workflow-runs/run-create.d.ts.map +1 -1
  153. package/dist/db/workflow-runs/run-create.js +159 -32
  154. package/dist/db/workflow-runs/run-create.js.map +1 -1
  155. package/dist/db/workflow-runs/run-rerun.d.ts.map +1 -1
  156. package/dist/db/workflow-runs/run-rerun.js +13 -5
  157. package/dist/db/workflow-runs/run-rerun.js.map +1 -1
  158. package/dist/db/workflow-runs/shared.d.ts +1 -0
  159. package/dist/db/workflow-runs/shared.d.ts.map +1 -1
  160. package/dist/db/workflow-runs/shared.js +2 -1
  161. package/dist/db/workflow-runs/shared.js.map +1 -1
  162. package/dist/db/workflow-runs/steps.js +3 -3
  163. package/dist/db/workflow-runs/steps.js.map +1 -1
  164. package/dist/db/workflow-runs.d.ts +4 -3
  165. package/dist/db/workflow-runs.d.ts.map +1 -1
  166. package/dist/db/workflow-runs.js +3 -2
  167. package/dist/db/workflow-runs.js.map +1 -1
  168. package/dist/metrics/instance.d.ts +1 -0
  169. package/dist/metrics/instance.d.ts.map +1 -1
  170. package/dist/metrics/instance.js +9 -0
  171. package/dist/metrics/instance.js.map +1 -1
  172. package/dist/presentation/dto/checkout-token.d.ts +1 -0
  173. package/dist/presentation/dto/checkout-token.d.ts.map +1 -1
  174. package/dist/presentation/dto/checkout-token.js +1 -0
  175. package/dist/presentation/dto/checkout-token.js.map +1 -1
  176. package/dist/presentation/dto/index.d.ts +1 -1
  177. package/dist/presentation/dto/index.d.ts.map +1 -1
  178. package/dist/presentation/dto/index.js +1 -1
  179. package/dist/presentation/dto/index.js.map +1 -1
  180. package/dist/presentation/dto/step.d.ts.map +1 -1
  181. package/dist/presentation/dto/step.js +2 -2
  182. package/dist/presentation/dto/step.js.map +1 -1
  183. package/dist/presentation/dto/workflow-run.d.ts +3 -1
  184. package/dist/presentation/dto/workflow-run.d.ts.map +1 -1
  185. package/dist/presentation/dto/workflow-run.js +34 -0
  186. package/dist/presentation/dto/workflow-run.js.map +1 -1
  187. package/dist/presentation/inter-module.d.ts.map +1 -1
  188. package/dist/presentation/inter-module.js +31 -3
  189. package/dist/presentation/inter-module.js.map +1 -1
  190. package/dist/presentation/routes/checkout-token.d.ts +1 -1
  191. package/dist/presentation/routes/checkout-token.d.ts.map +1 -1
  192. package/dist/presentation/routes/checkout-token.js +32 -20
  193. package/dist/presentation/routes/checkout-token.js.map +1 -1
  194. package/dist/presentation/routes/leased-step.d.ts +2 -0
  195. package/dist/presentation/routes/leased-step.d.ts.map +1 -1
  196. package/dist/presentation/routes/leased-step.js +2 -1
  197. package/dist/presentation/routes/leased-step.js.map +1 -1
  198. package/dist/presentation/routes/list-runs.d.ts.map +1 -1
  199. package/dist/presentation/routes/list-runs.js +9 -3
  200. package/dist/presentation/routes/list-runs.js.map +1 -1
  201. package/dist/presentation/routes/project-access.d.ts +1 -0
  202. package/dist/presentation/routes/project-access.d.ts.map +1 -1
  203. package/dist/presentation/routes/report-step.d.ts.map +1 -1
  204. package/dist/presentation/routes/report-step.js +9 -2
  205. package/dist/presentation/routes/report-step.js.map +1 -1
  206. package/dist/presentation/subscribers/on-job-steps-settled.js +1 -1
  207. package/dist/presentation/subscribers/on-job-steps-settled.js.map +1 -1
  208. package/dist/presentation/subscribers/on-runner-job-claimed.d.ts.map +1 -1
  209. package/dist/presentation/subscribers/on-runner-job-claimed.js +21 -0
  210. package/dist/presentation/subscribers/on-runner-job-claimed.js.map +1 -1
  211. package/dist/temporal/activities/index.d.ts.map +1 -1
  212. package/dist/temporal/activities/index.js +2 -1
  213. package/dist/temporal/activities/index.js.map +1 -1
  214. package/dist/temporal/activities/orchestration-activities.d.ts +1 -0
  215. package/dist/temporal/activities/orchestration-activities.d.ts.map +1 -1
  216. package/dist/temporal/activities/orchestration-activities.js.map +1 -1
  217. package/dist/temporal/constants.d.ts +1 -0
  218. package/dist/temporal/constants.d.ts.map +1 -1
  219. package/dist/temporal/constants.js +1 -0
  220. package/dist/temporal/constants.js.map +1 -1
  221. package/dist/temporal/index.d.ts +1 -1
  222. package/dist/temporal/index.d.ts.map +1 -1
  223. package/dist/temporal/index.js +1 -1
  224. package/dist/temporal/index.js.map +1 -1
  225. package/dist/temporal/workflows/index.bundle.js +82 -43
  226. package/dist/temporal/workflows/index.d.ts +1 -1
  227. package/dist/temporal/workflows/index.d.ts.map +1 -1
  228. package/dist/temporal/workflows/index.js +1 -1
  229. package/dist/temporal/workflows/index.js.map +1 -1
  230. package/dist/temporal/workflows/job-execution-orchestration.d.ts +5 -0
  231. package/dist/temporal/workflows/job-execution-orchestration.d.ts.map +1 -1
  232. package/dist/temporal/workflows/job-execution-orchestration.js +77 -43
  233. package/dist/temporal/workflows/job-execution-orchestration.js.map +1 -1
  234. package/dist/temporal/workflows/test-env.d.ts +5 -1
  235. package/dist/temporal/workflows/test-env.d.ts.map +1 -1
  236. package/dist/temporal/workflows/test-env.js +32 -11
  237. package/dist/temporal/workflows/test-env.js.map +1 -1
  238. package/dist/tsconfig.test.tsbuildinfo +1 -1
  239. package/drizzle/0000_initial.sql +14 -2
  240. package/drizzle/0001_windy_sunfire.sql +1 -0
  241. package/drizzle/meta/0000_snapshot.json +93 -1
  242. package/drizzle/meta/0001_snapshot.json +1711 -0
  243. package/drizzle/meta/_journal.json +2 -2
  244. package/package.json +21 -21
  245. package/src/core/agent-defaults.ts +2 -1
  246. package/src/core/checkout.test.ts +378 -67
  247. package/src/core/checkout.ts +142 -59
  248. package/src/core/entities/job-execution.test.ts +21 -0
  249. package/src/core/entities/job-execution.ts +24 -0
  250. package/src/core/entities/job-listener-event.ts +3 -0
  251. package/src/core/entities/step.ts +15 -3
  252. package/src/core/entities/workflow-run-attempt.ts +1 -0
  253. package/src/core/entities/workflow-run.ts +16 -0
  254. package/src/core/errors.ts +21 -7
  255. package/src/core/job-execution.ts +27 -4
  256. package/src/core/job-transition/decide-job-activation.test.ts +4 -0
  257. package/src/core/job-transition/decide-job-activation.ts +2 -0
  258. package/src/core/job-transition/derive-job-success.test.ts +12 -0
  259. package/src/core/job-transition/derive-job-success.ts +6 -9
  260. package/src/core/listener-execution-materialization.test.ts +2 -0
  261. package/src/core/listener-execution-materialization.ts +57 -11
  262. package/src/core/resolve-trigger-reference.test.ts +160 -0
  263. package/src/core/resolve-trigger-reference.ts +53 -0
  264. package/src/core/run-workflow.ts +2 -0
  265. package/src/core/step-config/agent.ts +29 -12
  266. package/src/core/step-config/assemble-run-context.test.ts +149 -6
  267. package/src/core/step-config/assemble-run-context.ts +87 -25
  268. package/src/core/step-config/complete-step-dispatch-config.test.ts +125 -2
  269. package/src/core/step-config/complete-step-dispatch-config.ts +83 -1
  270. package/src/core/step-config/index.ts +7 -0
  271. package/src/core/step-config/materialize-job-execution-steps.test.ts +250 -1
  272. package/src/core/step-config/materialize-job-execution-steps.ts +57 -10
  273. package/src/core/step-config/materialize-workflow-model.test.ts +212 -4
  274. package/src/core/step-config/materialize-workflow-model.ts +33 -28
  275. package/src/core/step-config/resolve-job-execution-name.test.ts +37 -15
  276. package/src/core/step-config/resolve-job-execution-name.ts +30 -15
  277. package/src/core/step-config/resolve-step-config.ts +175 -10
  278. package/src/core/step-config/resolve-workflow-run-name.test.ts +115 -0
  279. package/src/core/step-config/resolve-workflow-run-name.ts +108 -0
  280. package/src/core/step-transition/decide-step-transition.ts +2 -2
  281. package/src/core/step-transition/evaluate-gate.test.ts +8 -0
  282. package/src/core/step-transition/evaluate-gate.ts +8 -1
  283. package/src/core/workflow-run-creation.test.ts +7 -4
  284. package/src/core/workflow-run-creation.ts +13 -7
  285. package/src/db/db.ts +2 -0
  286. package/src/db/index.ts +6 -0
  287. package/src/db/job-listener-events.test.ts +19 -0
  288. package/src/db/job-listener-events.ts +3 -0
  289. package/src/db/job-listeners.test.ts +187 -5
  290. package/src/db/job-listeners.ts +122 -30
  291. package/src/db/schema/job-executions.ts +12 -5
  292. package/src/db/schema/job-listener-events.ts +3 -0
  293. package/src/db/schema/step-attempts.ts +2 -2
  294. package/src/db/schema/steps.ts +2 -1
  295. package/src/db/schema/workflow-run-attempts.ts +2 -0
  296. package/src/db/schema/workflow-run-counters.ts +13 -0
  297. package/src/db/schema/workflow-runs.ts +11 -2
  298. package/src/db/workflow-runs/job-executions.ts +37 -15
  299. package/src/db/workflow-runs/jobs.ts +17 -4
  300. package/src/db/workflow-runs/queries.test.ts +206 -0
  301. package/src/db/workflow-runs/queries.ts +146 -2
  302. package/src/db/workflow-runs/run-create.test.ts +606 -8
  303. package/src/db/workflow-runs/run-create.ts +185 -40
  304. package/src/db/workflow-runs/run-rerun.test.ts +61 -2
  305. package/src/db/workflow-runs/run-rerun.ts +15 -5
  306. package/src/db/workflow-runs/shared.ts +2 -0
  307. package/src/db/workflow-runs/steps.ts +3 -3
  308. package/src/db/workflow-runs.ts +7 -0
  309. package/src/metrics/instance.ts +14 -0
  310. package/src/presentation/dto/checkout-token.test.ts +19 -9
  311. package/src/presentation/dto/checkout-token.ts +2 -1
  312. package/src/presentation/dto/index.ts +1 -1
  313. package/src/presentation/dto/job.test.ts +9 -0
  314. package/src/presentation/dto/step.test.ts +12 -0
  315. package/src/presentation/dto/step.ts +5 -2
  316. package/src/presentation/dto/workflow-run.ts +44 -2
  317. package/src/presentation/inter-module.test.ts +165 -0
  318. package/src/presentation/inter-module.ts +38 -4
  319. package/src/presentation/routes/checkout-token.test.ts +357 -142
  320. package/src/presentation/routes/checkout-token.ts +56 -26
  321. package/src/presentation/routes/get-run.test.ts +2 -0
  322. package/src/presentation/routes/get-step-secrets.test.ts +7 -2
  323. package/src/presentation/routes/leased-step.ts +9 -1
  324. package/src/presentation/routes/list-runs.test.ts +57 -0
  325. package/src/presentation/routes/list-runs.ts +8 -3
  326. package/src/presentation/routes/report-step.test.ts +25 -0
  327. package/src/presentation/routes/report-step.ts +10 -2
  328. package/src/presentation/subscribers/on-job-steps-settled.ts +1 -1
  329. package/src/presentation/subscribers/on-runner-job-claimed.test.ts +49 -0
  330. package/src/presentation/subscribers/on-runner-job-claimed.ts +22 -0
  331. package/src/temporal/activities/index.ts +1 -0
  332. package/src/temporal/activities/orchestration-activities.ts +1 -0
  333. package/src/temporal/constants.ts +1 -0
  334. package/src/temporal/index.ts +1 -0
  335. package/src/temporal/workflows/index.ts +1 -0
  336. package/src/temporal/workflows/job-execution-orchestration.test.ts +142 -6
  337. package/src/temporal/workflows/job-execution-orchestration.ts +99 -50
  338. package/src/temporal/workflows/run-orchestration.test.ts +1 -1
  339. package/src/temporal/workflows/test-env.ts +50 -13
  340. package/test/factories/project.ts +2 -0
  341. package/test/factories/workflow-model.ts +80 -26
  342. package/test/factories/workflow-run.ts +4 -1
  343. package/test/fixtures/agent-inter-module.ts +2 -1
  344. package/test/fixtures/job-with-steps.ts +1 -1
  345. package/tsconfig.build.tsbuildinfo +1 -1
  346. package/drizzle/0001_agent_tool_materialization.sql +0 -1
@@ -1,4 +1,4 @@
1
- export { jobExecutionOrchestration, jobFinishedSignal, jobLeaseExpiredSignal, } from './job-execution-orchestration.js';
1
+ export { jobClaimedSignal, jobExecutionOrchestration, jobFinishedSignal, jobLeaseExpiredSignal, } from './job-execution-orchestration.js';
2
2
  export { jobListenerOrchestration, listenerEventsAvailableSignal, listenerResolveSignal, } from './job-listener-orchestration.js';
3
3
  export { runOrchestration } from './run-orchestration.js';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/temporal/workflows/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,GACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/temporal/workflows/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,wBAAwB,EACxB,6BAA6B,EAC7B,qBAAqB,GACtB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAC,gBAAgB,EAAC,MAAM,wBAAwB,CAAC"}
@@ -1,4 +1,4 @@
1
- export { jobExecutionOrchestration, jobFinishedSignal, jobLeaseExpiredSignal } from './job-execution-orchestration.js';
1
+ export { jobClaimedSignal, jobExecutionOrchestration, jobFinishedSignal, jobLeaseExpiredSignal } from './job-execution-orchestration.js';
2
2
  export { jobListenerOrchestration, listenerEventsAvailableSignal, listenerResolveSignal } from './job-listener-orchestration.js';
3
3
  export { runOrchestration } from './run-orchestration.js';
4
4
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/temporal/workflows/index.ts"],"sourcesContent":["export {\n jobExecutionOrchestration,\n jobFinishedSignal,\n jobLeaseExpiredSignal,\n} from './job-execution-orchestration.js';\nexport {\n jobListenerOrchestration,\n listenerEventsAvailableSignal,\n listenerResolveSignal,\n} from './job-listener-orchestration.js';\nexport {runOrchestration} from './run-orchestration.js';\n"],"names":["jobExecutionOrchestration","jobFinishedSignal","jobLeaseExpiredSignal","jobListenerOrchestration","listenerEventsAvailableSignal","listenerResolveSignal","runOrchestration"],"mappings":"AAAA,SACEA,yBAAyB,EACzBC,iBAAiB,EACjBC,qBAAqB,QAChB,mCAAmC;AAC1C,SACEC,wBAAwB,EACxBC,6BAA6B,EAC7BC,qBAAqB,QAChB,kCAAkC;AACzC,SAAQC,gBAAgB,QAAO,yBAAyB"}
1
+ {"version":3,"sources":["../../../src/temporal/workflows/index.ts"],"sourcesContent":["export {\n jobClaimedSignal,\n jobExecutionOrchestration,\n jobFinishedSignal,\n jobLeaseExpiredSignal,\n} from './job-execution-orchestration.js';\nexport {\n jobListenerOrchestration,\n listenerEventsAvailableSignal,\n listenerResolveSignal,\n} from './job-listener-orchestration.js';\nexport {runOrchestration} from './run-orchestration.js';\n"],"names":["jobClaimedSignal","jobExecutionOrchestration","jobFinishedSignal","jobLeaseExpiredSignal","jobListenerOrchestration","listenerEventsAvailableSignal","listenerResolveSignal","runOrchestration"],"mappings":"AAAA,SACEA,gBAAgB,EAChBC,yBAAyB,EACzBC,iBAAiB,EACjBC,qBAAqB,QAChB,mCAAmC;AAC1C,SACEC,wBAAwB,EACxBC,6BAA6B,EAC7BC,qBAAqB,QAChB,kCAAkC;AACzC,SAAQC,gBAAgB,QAAO,yBAAyB"}
@@ -6,6 +6,11 @@ export declare const jobFinishedSignal: import("@temporalio/common").SignalDefin
6
6
  export declare const jobLeaseExpiredSignal: import("@temporalio/common").SignalDefinition<[{
7
7
  jobExecutionId?: string | undefined;
8
8
  }], string>;
9
+ export interface JobClaimedSignalPayload {
10
+ jobExecutionId: string;
11
+ claimedAt: string;
12
+ }
13
+ export declare const jobClaimedSignal: import("@temporalio/common").SignalDefinition<[JobClaimedSignalPayload], string>;
9
14
  export interface JobExecutionOrchestrationInput {
10
15
  workspaceId: string;
11
16
  workflowRunId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"job-execution-orchestration.d.ts","sourceRoot":"","sources":["../../../src/temporal/workflows/job-execution-orchestration.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,0CAA0C,CAAC;AAoDtF,eAAO,MAAM,iBAAiB;YACL,uBAAuB;qBAAmB,MAAM,GAAG,SAAS;WAElF,CAAC;AACJ,eAAO,MAAM,qBAAqB;qBACA,MAAM,GAAG,SAAS;WAA6B,CAAC;AAElF,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,uBAAuB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAyMD,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CA0B1C"}
1
+ {"version":3,"file":"job-execution-orchestration.d.ts","sourceRoot":"","sources":["../../../src/temporal/workflows/job-execution-orchestration.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,0CAA0C,CAAC;AAoDtF,eAAO,MAAM,iBAAiB;YACL,uBAAuB;qBAAmB,MAAM,GAAG,SAAS;WAElF,CAAC;AACJ,eAAO,MAAM,qBAAqB;qBACA,MAAM,GAAG,SAAS;WAA6B,CAAC;AAClF,MAAM,WAAW,uBAAuB;IACtC,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACnB;AACD,eAAO,MAAM,gBAAgB,kFAA8D,CAAC;AAE5F,MAAM,WAAW,8BAA8B;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,MAAM,CAAC;IACzB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAC/C,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACvC,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,+BAA+B;IAC9C,MAAM,EAAE,uBAAuB,CAAC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAwND,wBAAsB,yBAAyB,CAC7C,KAAK,EAAE,8BAA8B,GACpC,OAAO,CAAC,+BAA+B,CAAC,CAuD1C"}
@@ -1,24 +1,24 @@
1
1
  import { ApplicationFailure } from '@temporalio/common';
2
2
  import { condition, defineSignal, log, proxyActivities, setHandler } from '@temporalio/workflow';
3
3
  import { hasNoRequiredRunnerLabels, jobExecutionStartOutcome, resolveJobExecutionOutcomeSignal } from '#core/job-execution-outcome.js';
4
- import { JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL } from '../constants.js';
4
+ import { JOB_CLAIMED_SIGNAL, JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL } from '../constants.js';
5
+ import { remainingMs } from './deadline.js';
5
6
  /**
6
- * Two signals, one precedence ladder, then best-effort lease release:
7
+ * Enqueue, wait for the runner claim, then wait for one of the terminal facts:
7
8
  *
8
- * job-finished (recordStepResult exhausted the steps) ─┐
9
- * job-lease-expired (runner heartbeat went stale) ─────┤
10
- *
11
- * condition(finished ∥ leaseExpired, executionTimeout)
12
- * ├─ finished → setJobExecutionStatus(status) + resolve job status ─┐
13
- * ├─ leaseExpired → resolveLeaseExpiredJobExecutionActivity ─┤→ releaseLease
14
- * └─ neither (6h) → failJobExecutionAsTimedOutActivity + sweep steps (NO release; the
15
- * TIMED_OUT event drives cooperative cancel, the detector reaps)
9
+ * enqueue ──> PENDING ── job-claimed ──> RUNNING
10
+ * │ │
11
+ * │ timeout ├─ job-finished
12
+ * │ ├─ job-lease-expired
13
+ * ▼ └─ timeout
14
+ * TERMINAL
16
15
  *
17
- * Both signals can be delivered before condition() resumes (independent outboxes,
18
- * no ordering), so finished is evaluated FIRST: a genuinely-finished job is never
19
- * flipped to failed by a late lease-expiry. releaseLease is best-effort a runners
20
- * DB outage must never block the child workflow from returning the job outcome to
21
- * run-orchestration; a leftover lease row is reaped by the stuck detector.
16
+ * The claim signal is the runner-owned lifecycle boundary. The workflow keeps the
17
+ * execution pending while it is queued, then performs the versioned pending → running
18
+ * transition after the current claim. One deadline spans both waits; claim never resets
19
+ * it. Signals can arrive in any order, so the precedence is finished > lease expired >
20
+ * claimed > timeout. Lease cleanup remains best-effort: a runners DB outage must never
21
+ * block the child workflow from returning the job outcome to run-orchestration.
22
22
  */ const { setJobStatus, setJobExecutionStatus, enqueueJobExecutionForRunner, bulkSetStepStatuses, failJobExecutionAsTimedOutActivity, resolveLeaseExpiredJobExecutionActivity } = proxyActivities({
23
23
  startToCloseTimeout: '30s'
24
24
  });
@@ -40,6 +40,7 @@ const { releaseLeaseActivity } = proxyActivities({
40
40
  const DEFAULT_EXECUTION_MAX_DURATION_MS = 6 * 60 * 60 * 1000;
41
41
  export const jobFinishedSignal = defineSignal(JOB_FINISHED_SIGNAL);
42
42
  export const jobLeaseExpiredSignal = defineSignal(JOB_LEASE_EXPIRED_SIGNAL);
43
+ export const jobClaimedSignal = defineSignal(JOB_CLAIMED_SIGNAL);
43
44
  async function releaseLeaseBestEffort(jobExecutionId) {
44
45
  try {
45
46
  await releaseLeaseActivity({
@@ -75,10 +76,21 @@ async function resolveJobStatusOrFailClosed(input) {
75
76
  };
76
77
  }
77
78
  }
78
- async function markJobExecutionRunningAndEnqueue(input) {
79
+ async function enqueueJobExecution(input) {
79
80
  if (hasNoRequiredRunnerLabels(input.requiredLabels)) {
80
81
  throw ApplicationFailure.nonRetryable(`Job ${input.jobId} has no required runner labels`, 'EmptyRequiredLabelsError');
81
82
  }
83
+ await enqueueJobExecutionForRunner({
84
+ workspaceId: input.workspaceId,
85
+ workflowRunId: input.workflowRunId,
86
+ runAttemptId: input.runAttemptId,
87
+ jobId: input.jobId,
88
+ jobExecutionId: input.jobExecutionId,
89
+ projectId: input.projectId,
90
+ requiredLabels: input.requiredLabels
91
+ });
92
+ }
93
+ async function markJobExecutionRunning(input) {
82
94
  const { newVersion: runningVersion, status } = await setJobExecutionStatus({
83
95
  jobExecutionId: input.jobExecutionId,
84
96
  status: 'running',
@@ -89,38 +101,27 @@ async function markJobExecutionRunningAndEnqueue(input) {
89
101
  status
90
102
  });
91
103
  if (start.kind === 'terminal') return start;
92
- await enqueueJobExecutionForRunner({
93
- workspaceId: input.workspaceId,
94
- workflowRunId: input.workflowRunId,
95
- runAttemptId: input.runAttemptId,
96
- jobId: input.jobId,
97
- jobExecutionId: input.jobExecutionId,
98
- projectId: input.projectId,
99
- requiredLabels: input.requiredLabels
100
- });
101
104
  return {
102
105
  kind: 'running',
103
106
  runningVersion
104
107
  };
105
108
  }
106
- // Both signals can arrive before condition() resumes (independent outboxes, no
107
- // ordering), so callers must evaluate `finished` before `leaseExpired`.
108
- async function awaitJobOutcome(jobExecutionId, timeoutMs) {
109
- let finished;
110
- let leaseExpired = false;
109
+ function registerJobExecutionSignalHandlers(jobExecutionId, signals) {
111
110
  setHandler(jobFinishedSignal, (payload)=>{
112
111
  if (payload.jobExecutionId !== undefined && payload.jobExecutionId !== jobExecutionId) return;
113
- finished ??= payload;
112
+ signals.finished ??= payload;
114
113
  });
115
114
  setHandler(jobLeaseExpiredSignal, (payload = {})=>{
116
115
  if (payload.jobExecutionId !== undefined && payload.jobExecutionId !== jobExecutionId) return;
117
- leaseExpired = true;
116
+ signals.leaseExpired = true;
118
117
  });
119
- await condition(()=>finished !== undefined || leaseExpired, timeoutMs);
120
- return {
121
- finished,
122
- leaseExpired
123
- };
118
+ setHandler(jobClaimedSignal, (payload)=>{
119
+ if (payload.jobExecutionId !== jobExecutionId) return;
120
+ signals.claimed ??= payload;
121
+ });
122
+ }
123
+ async function waitForJobExecutionSignal(signals, deadline, includeClaim) {
124
+ await condition(()=>signals.finished !== undefined || signals.leaseExpired || includeClaim && signals.claimed !== undefined, remainingMs(deadline) ?? 0);
124
125
  }
125
126
  async function resolveFinishedJobExecution({ input, runningVersion, status }) {
126
127
  await setJobExecutionStatus({
@@ -225,7 +226,43 @@ async function resolveTimedOutJobExecution({ input, runningVersion }) {
225
226
  };
226
227
  }
227
228
  export async function jobExecutionOrchestration(input) {
228
- const running = await markJobExecutionRunningAndEnqueue(input);
229
+ const signals = {
230
+ finished: undefined,
231
+ leaseExpired: false,
232
+ claimed: undefined
233
+ };
234
+ // Register every signal before enqueue can block or publish a claim/outcome event. The
235
+ // handlers retain signals that arrive while the enqueue activity is in flight.
236
+ registerJobExecutionSignalHandlers(input.jobExecutionId, signals);
237
+ await enqueueJobExecution(input);
238
+ const timeoutMs = input.executionTimeoutMs ?? DEFAULT_EXECUTION_MAX_DURATION_MS;
239
+ const deadline = Date.now() + timeoutMs;
240
+ await waitForJobExecutionSignal(signals, deadline, true);
241
+ // A terminal fact wins over claim even when both signals arrive before the condition
242
+ // resumes. This prevents a late claim from reopening an execution that already finished.
243
+ let resolution = resolveJobExecutionOutcomeSignal(signals);
244
+ if (resolution === 'finished') {
245
+ const { finished } = signals;
246
+ if (finished === undefined) throw new Error('Missing finished signal for finished resolution');
247
+ return resolveFinishedJobExecution({
248
+ input,
249
+ runningVersion: input.executionVersion,
250
+ status: finished.status
251
+ });
252
+ }
253
+ if (resolution === 'lease-expired') {
254
+ return resolveLeaseExpiredJobExecution({
255
+ input,
256
+ runningVersion: input.executionVersion
257
+ });
258
+ }
259
+ if (!signals.claimed) {
260
+ return resolveTimedOutJobExecution({
261
+ input,
262
+ runningVersion: input.executionVersion
263
+ });
264
+ }
265
+ const running = await markJobExecutionRunning(input);
229
266
  if (running.kind === 'terminal') {
230
267
  if (input.resolveJobStatus === false) {
231
268
  return {
@@ -236,11 +273,8 @@ export async function jobExecutionOrchestration(input) {
236
273
  return running.result;
237
274
  }
238
275
  const { runningVersion } = running;
239
- const timeoutMs = input.executionTimeoutMs ?? DEFAULT_EXECUTION_MAX_DURATION_MS;
240
- const signals = await awaitJobOutcome(input.jobExecutionId, timeoutMs);
241
- // Precedence ladder: a genuinely-finished job is never flipped to failed by a
242
- // late lease-expiry, so `finished` wins over `leaseExpired`.
243
- const resolution = resolveJobExecutionOutcomeSignal(signals);
276
+ await waitForJobExecutionSignal(signals, deadline, false);
277
+ resolution = resolveJobExecutionOutcomeSignal(signals);
244
278
  if (resolution === 'finished') {
245
279
  const { finished } = signals;
246
280
  if (finished === undefined) throw new Error('Missing finished signal for finished resolution');
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/temporal/workflows/job-execution-orchestration.ts"],"sourcesContent":["import {ApplicationFailure} from '@temporalio/common';\nimport {condition, defineSignal, log, proxyActivities, setHandler} from '@temporalio/workflow';\nimport {\n hasNoRequiredRunnerLabels,\n type JobExecutionOutcomeSignals,\n jobExecutionStartOutcome,\n resolveJobExecutionOutcomeSignal,\n} from '#core/job-execution-outcome.js';\nimport type {RuntimeCompletionStatus} from '#core/workflow-scheduling/runtime-dag.js';\n\nimport type {createOrchestrationActivities} from '../activities/index.js';\nimport {JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL} from '../constants.js';\n\n/**\n * Two signals, one precedence ladder, then best-effort lease release:\n *\n * job-finished (recordStepResult exhausted the steps) ─┐\n * job-lease-expired (runner heartbeat went stale) ─────┤\n * ▼\n * condition(finished ∥ leaseExpired, executionTimeout)\n * ├─ finished → setJobExecutionStatus(status) + resolve job status ─┐\n * ├─ leaseExpired → resolveLeaseExpiredJobExecutionActivity ─┤→ releaseLease\n * └─ neither (6h) → failJobExecutionAsTimedOutActivity + sweep steps (NO release; the\n * TIMED_OUT event drives cooperative cancel, the detector reaps)\n *\n * Both signals can be delivered before condition() resumes (independent outboxes,\n * no ordering), so finished is evaluated FIRST: a genuinely-finished job is never\n * flipped to failed by a late lease-expiry. releaseLease is best-effort — a runners\n * DB outage must never block the child workflow from returning the job outcome to\n * run-orchestration; a leftover lease row is reaped by the stuck detector.\n */\n\nconst {\n setJobStatus,\n setJobExecutionStatus,\n enqueueJobExecutionForRunner,\n bulkSetStepStatuses,\n failJobExecutionAsTimedOutActivity,\n resolveLeaseExpiredJobExecutionActivity,\n} = proxyActivities<ReturnType<typeof createOrchestrationActivities>>({\n startToCloseTimeout: '30s',\n});\n\nconst {resolveJobStatusFromJobExecutionsActivity} = proxyActivities<\n ReturnType<typeof createOrchestrationActivities>\n>({\n startToCloseTimeout: '30s',\n retry: {maximumAttempts: 5},\n});\n\n// Lease cleanup gets a bounded retry policy of its own: after a few attempts the\n// workflow stops waiting on it (see releaseLeaseBestEffort) rather than blocking\n// the DAG on runners-side availability.\nconst {releaseLeaseActivity} = proxyActivities<ReturnType<typeof createOrchestrationActivities>>({\n startToCloseTimeout: '30s',\n retry: {maximumAttempts: 5},\n});\n\nconst DEFAULT_EXECUTION_MAX_DURATION_MS = 6 * 60 * 60 * 1000;\n\nexport const jobFinishedSignal =\n defineSignal<[{status: RuntimeCompletionStatus; jobExecutionId?: string | undefined}]>(\n JOB_FINISHED_SIGNAL,\n );\nexport const jobLeaseExpiredSignal =\n defineSignal<[{jobExecutionId?: string | undefined}]>(JOB_LEASE_EXPIRED_SIGNAL);\n\nexport interface JobExecutionOrchestrationInput {\n workspaceId: string;\n workflowRunId: string;\n runAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n jobVersion: number;\n executionVersion: number;\n executionTimeoutMs?: number | null | undefined;\n resolveJobStatus?: boolean | undefined;\n requiredLabels: string[];\n}\n\nexport interface JobExecutionOrchestrationResult {\n status: RuntimeCompletionStatus;\n jobVersion: number;\n}\n\nasync function releaseLeaseBestEffort(jobExecutionId: string): Promise<void> {\n try {\n await releaseLeaseActivity({jobExecutionId});\n } catch (err) {\n log.warn('lease release failed; stuck detector will reap the row', {\n jobExecutionId,\n error: String(err),\n });\n }\n}\n\nasync function resolveJobStatusOrFailClosed(\n input: JobExecutionOrchestrationInput,\n): Promise<{status: RuntimeCompletionStatus; jobVersion: number}> {\n try {\n return await resolveJobStatusFromJobExecutionsActivity({jobId: input.jobId});\n } catch (err) {\n log.error('job status resolution failed; failing job closed', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n error: String(err),\n });\n const {newVersion} = await setJobStatus({\n jobId: input.jobId,\n status: 'failed',\n version: input.jobVersion,\n statusReason: 'step_failed',\n });\n return {status: 'failed', jobVersion: newVersion};\n }\n}\n\nasync function markJobExecutionRunningAndEnqueue(\n input: JobExecutionOrchestrationInput,\n): Promise<\n | {kind: 'running'; runningVersion: number}\n | {kind: 'terminal'; result: JobExecutionOrchestrationResult}\n> {\n if (hasNoRequiredRunnerLabels(input.requiredLabels)) {\n throw ApplicationFailure.nonRetryable(\n `Job ${input.jobId} has no required runner labels`,\n 'EmptyRequiredLabelsError',\n );\n }\n\n const {newVersion: runningVersion, status} = await setJobExecutionStatus({\n jobExecutionId: input.jobExecutionId,\n status: 'running',\n version: input.executionVersion,\n });\n\n const start = jobExecutionStartOutcome({newVersion: runningVersion, status});\n if (start.kind === 'terminal') return start;\n\n await enqueueJobExecutionForRunner({\n workspaceId: input.workspaceId,\n workflowRunId: input.workflowRunId,\n runAttemptId: input.runAttemptId,\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n projectId: input.projectId,\n requiredLabels: input.requiredLabels,\n });\n\n return {kind: 'running', runningVersion};\n}\n\n// Both signals can arrive before condition() resumes (independent outboxes, no\n// ordering), so callers must evaluate `finished` before `leaseExpired`.\nasync function awaitJobOutcome(\n jobExecutionId: string,\n timeoutMs: number,\n): Promise<JobExecutionOutcomeSignals> {\n let finished: {status: RuntimeCompletionStatus; jobExecutionId?: string | undefined} | undefined;\n let leaseExpired = false;\n setHandler(jobFinishedSignal, (payload) => {\n if (payload.jobExecutionId !== undefined && payload.jobExecutionId !== jobExecutionId) return;\n finished ??= payload;\n });\n setHandler(jobLeaseExpiredSignal, (payload = {}) => {\n if (payload.jobExecutionId !== undefined && payload.jobExecutionId !== jobExecutionId) return;\n leaseExpired = true;\n });\n\n await condition(() => finished !== undefined || leaseExpired, timeoutMs);\n\n return {finished, leaseExpired};\n}\n\ninterface JobExecutionResolution {\n input: JobExecutionOrchestrationInput;\n runningVersion: number;\n}\n\nasync function resolveFinishedJobExecution({\n input,\n runningVersion,\n status,\n}: JobExecutionResolution & {\n status: RuntimeCompletionStatus;\n}): Promise<JobExecutionOrchestrationResult> {\n await setJobExecutionStatus({\n jobExecutionId: input.jobExecutionId,\n status: jobExecutionStatusForRuntimeStatus(status),\n version: runningVersion,\n statusReason: status === 'failed' ? 'step_failed' : null,\n });\n if (input.resolveJobStatus === false) {\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'finished',\n status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return {status, jobVersion: input.jobVersion};\n }\n const resolved = await resolveJobStatusOrFailClosed(input);\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'finished',\n status: resolved.status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return resolved;\n}\n\nfunction jobExecutionStatusForRuntimeStatus(\n status: RuntimeCompletionStatus,\n): 'succeeded' | 'failed' | 'cancelled' {\n if (status === 'succeeded' || status === 'failed' || status === 'cancelled') return status;\n throw ApplicationFailure.nonRetryable(\n `Job execution cannot be marked ${status}`,\n 'InvalidJobExecutionStatusError',\n );\n}\n\nasync function resolveLeaseExpiredJobExecution({\n input,\n runningVersion,\n}: JobExecutionResolution): Promise<JobExecutionOrchestrationResult> {\n const leaseExpired = await resolveLeaseExpiredJobExecutionActivity({\n jobExecutionId: input.jobExecutionId,\n expectedVersion: runningVersion,\n });\n if (input.resolveJobStatus === false) {\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'lease_expired',\n status: leaseExpired.status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return {status: leaseExpired.status, jobVersion: input.jobVersion};\n }\n const {status, jobVersion} = await resolveJobStatusOrFailClosed(input);\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'lease_expired',\n status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return {status, jobVersion};\n}\n\n// Timeout backstop. The activity atomically fails the execution, marks\n// `timed_out_at`, and enqueues WORKFLOWS_JOB_EXECUTION_TIMED_OUT; the runners subscriber\n// then asks the runner to cancel. The lease is intentionally NOT released here.\nasync function resolveTimedOutJobExecution({\n input,\n runningVersion,\n}: JobExecutionResolution): Promise<JobExecutionOrchestrationResult> {\n await failJobExecutionAsTimedOutActivity({\n jobExecutionId: input.jobExecutionId,\n runAttemptId: input.runAttemptId,\n expectedVersion: runningVersion,\n });\n await bulkSetStepStatuses({jobExecutionId: input.jobExecutionId, status: 'failed'});\n if (input.resolveJobStatus === false) {\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'max_duration',\n status: 'failed',\n });\n return {status: 'failed', jobVersion: input.jobVersion};\n }\n const {jobVersion} = await resolveJobStatusOrFailClosed(input);\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'max_duration',\n status: 'failed',\n });\n return {status: 'failed', jobVersion};\n}\n\nexport async function jobExecutionOrchestration(\n input: JobExecutionOrchestrationInput,\n): Promise<JobExecutionOrchestrationResult> {\n const running = await markJobExecutionRunningAndEnqueue(input);\n if (running.kind === 'terminal') {\n if (input.resolveJobStatus === false) {\n return {status: running.result.status, jobVersion: input.jobVersion};\n }\n return running.result;\n }\n const {runningVersion} = running;\n\n const timeoutMs = input.executionTimeoutMs ?? DEFAULT_EXECUTION_MAX_DURATION_MS;\n const signals = await awaitJobOutcome(input.jobExecutionId, timeoutMs);\n\n // Precedence ladder: a genuinely-finished job is never flipped to failed by a\n // late lease-expiry, so `finished` wins over `leaseExpired`.\n const resolution = resolveJobExecutionOutcomeSignal(signals);\n if (resolution === 'finished') {\n const {finished} = signals;\n if (finished === undefined) throw new Error('Missing finished signal for finished resolution');\n\n return resolveFinishedJobExecution({input, runningVersion, status: finished.status});\n }\n if (resolution === 'lease-expired') {\n return resolveLeaseExpiredJobExecution({input, runningVersion});\n }\n return resolveTimedOutJobExecution({input, runningVersion});\n}\n"],"names":["ApplicationFailure","condition","defineSignal","log","proxyActivities","setHandler","hasNoRequiredRunnerLabels","jobExecutionStartOutcome","resolveJobExecutionOutcomeSignal","JOB_FINISHED_SIGNAL","JOB_LEASE_EXPIRED_SIGNAL","setJobStatus","setJobExecutionStatus","enqueueJobExecutionForRunner","bulkSetStepStatuses","failJobExecutionAsTimedOutActivity","resolveLeaseExpiredJobExecutionActivity","startToCloseTimeout","resolveJobStatusFromJobExecutionsActivity","retry","maximumAttempts","releaseLeaseActivity","DEFAULT_EXECUTION_MAX_DURATION_MS","jobFinishedSignal","jobLeaseExpiredSignal","releaseLeaseBestEffort","jobExecutionId","err","warn","error","String","resolveJobStatusOrFailClosed","input","jobId","newVersion","status","version","jobVersion","statusReason","markJobExecutionRunningAndEnqueue","requiredLabels","nonRetryable","runningVersion","executionVersion","start","kind","workspaceId","workflowRunId","runAttemptId","projectId","awaitJobOutcome","timeoutMs","finished","leaseExpired","payload","undefined","resolveFinishedJobExecution","jobExecutionStatusForRuntimeStatus","resolveJobStatus","info","terminationReason","resolved","resolveLeaseExpiredJobExecution","expectedVersion","resolveTimedOutJobExecution","jobExecutionOrchestration","running","result","executionTimeoutMs","signals","resolution","Error"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/temporal/workflows/job-execution-orchestration.ts"],"sourcesContent":["import {ApplicationFailure} from '@temporalio/common';\nimport {condition, defineSignal, log, proxyActivities, setHandler} from '@temporalio/workflow';\nimport {\n hasNoRequiredRunnerLabels,\n type JobExecutionOutcomeSignals,\n jobExecutionStartOutcome,\n resolveJobExecutionOutcomeSignal,\n} from '#core/job-execution-outcome.js';\nimport type {RuntimeCompletionStatus} from '#core/workflow-scheduling/runtime-dag.js';\n\nimport type {createOrchestrationActivities} from '../activities/index.js';\nimport {JOB_CLAIMED_SIGNAL, JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL} from '../constants.js';\nimport {remainingMs} from './deadline.js';\n\n/**\n * Enqueue, wait for the runner claim, then wait for one of the terminal facts:\n *\n * enqueue ──> PENDING ── job-claimed ──> RUNNING\n * │ │\n * │ timeout ├─ job-finished\n * │ ├─ job-lease-expired\n * ▼ └─ timeout\n * TERMINAL\n *\n * The claim signal is the runner-owned lifecycle boundary. The workflow keeps the\n * execution pending while it is queued, then performs the versioned pending → running\n * transition after the current claim. One deadline spans both waits; claim never resets\n * it. Signals can arrive in any order, so the precedence is finished > lease expired >\n * claimed > timeout. Lease cleanup remains best-effort: a runners DB outage must never\n * block the child workflow from returning the job outcome to run-orchestration.\n */\n\nconst {\n setJobStatus,\n setJobExecutionStatus,\n enqueueJobExecutionForRunner,\n bulkSetStepStatuses,\n failJobExecutionAsTimedOutActivity,\n resolveLeaseExpiredJobExecutionActivity,\n} = proxyActivities<ReturnType<typeof createOrchestrationActivities>>({\n startToCloseTimeout: '30s',\n});\n\nconst {resolveJobStatusFromJobExecutionsActivity} = proxyActivities<\n ReturnType<typeof createOrchestrationActivities>\n>({\n startToCloseTimeout: '30s',\n retry: {maximumAttempts: 5},\n});\n\n// Lease cleanup gets a bounded retry policy of its own: after a few attempts the\n// workflow stops waiting on it (see releaseLeaseBestEffort) rather than blocking\n// the DAG on runners-side availability.\nconst {releaseLeaseActivity} = proxyActivities<ReturnType<typeof createOrchestrationActivities>>({\n startToCloseTimeout: '30s',\n retry: {maximumAttempts: 5},\n});\n\nconst DEFAULT_EXECUTION_MAX_DURATION_MS = 6 * 60 * 60 * 1000;\n\nexport const jobFinishedSignal =\n defineSignal<[{status: RuntimeCompletionStatus; jobExecutionId?: string | undefined}]>(\n JOB_FINISHED_SIGNAL,\n );\nexport const jobLeaseExpiredSignal =\n defineSignal<[{jobExecutionId?: string | undefined}]>(JOB_LEASE_EXPIRED_SIGNAL);\nexport interface JobClaimedSignalPayload {\n jobExecutionId: string;\n claimedAt: string;\n}\nexport const jobClaimedSignal = defineSignal<[JobClaimedSignalPayload]>(JOB_CLAIMED_SIGNAL);\n\nexport interface JobExecutionOrchestrationInput {\n workspaceId: string;\n workflowRunId: string;\n runAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n jobVersion: number;\n executionVersion: number;\n executionTimeoutMs?: number | null | undefined;\n resolveJobStatus?: boolean | undefined;\n requiredLabels: string[];\n}\n\nexport interface JobExecutionOrchestrationResult {\n status: RuntimeCompletionStatus;\n jobVersion: number;\n}\n\nasync function releaseLeaseBestEffort(jobExecutionId: string): Promise<void> {\n try {\n await releaseLeaseActivity({jobExecutionId});\n } catch (err) {\n log.warn('lease release failed; stuck detector will reap the row', {\n jobExecutionId,\n error: String(err),\n });\n }\n}\n\nasync function resolveJobStatusOrFailClosed(\n input: JobExecutionOrchestrationInput,\n): Promise<{status: RuntimeCompletionStatus; jobVersion: number}> {\n try {\n return await resolveJobStatusFromJobExecutionsActivity({jobId: input.jobId});\n } catch (err) {\n log.error('job status resolution failed; failing job closed', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n error: String(err),\n });\n const {newVersion} = await setJobStatus({\n jobId: input.jobId,\n status: 'failed',\n version: input.jobVersion,\n statusReason: 'step_failed',\n });\n return {status: 'failed', jobVersion: newVersion};\n }\n}\n\nasync function enqueueJobExecution(input: JobExecutionOrchestrationInput): Promise<void> {\n if (hasNoRequiredRunnerLabels(input.requiredLabels)) {\n throw ApplicationFailure.nonRetryable(\n `Job ${input.jobId} has no required runner labels`,\n 'EmptyRequiredLabelsError',\n );\n }\n\n await enqueueJobExecutionForRunner({\n workspaceId: input.workspaceId,\n workflowRunId: input.workflowRunId,\n runAttemptId: input.runAttemptId,\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n projectId: input.projectId,\n requiredLabels: input.requiredLabels,\n });\n}\n\nasync function markJobExecutionRunning(\n input: JobExecutionOrchestrationInput,\n): Promise<\n | {kind: 'running'; runningVersion: number}\n | {kind: 'terminal'; result: JobExecutionOrchestrationResult}\n> {\n const {newVersion: runningVersion, status} = await setJobExecutionStatus({\n jobExecutionId: input.jobExecutionId,\n status: 'running',\n version: input.executionVersion,\n });\n\n const start = jobExecutionStartOutcome({newVersion: runningVersion, status});\n if (start.kind === 'terminal') return start;\n return {kind: 'running', runningVersion};\n}\n\ninterface JobExecutionSignals extends JobExecutionOutcomeSignals {\n claimed: JobClaimedSignalPayload | undefined;\n}\n\nfunction registerJobExecutionSignalHandlers(\n jobExecutionId: string,\n signals: JobExecutionSignals,\n): void {\n setHandler(jobFinishedSignal, (payload) => {\n if (payload.jobExecutionId !== undefined && payload.jobExecutionId !== jobExecutionId) return;\n signals.finished ??= payload;\n });\n setHandler(jobLeaseExpiredSignal, (payload = {}) => {\n if (payload.jobExecutionId !== undefined && payload.jobExecutionId !== jobExecutionId) return;\n signals.leaseExpired = true;\n });\n setHandler(jobClaimedSignal, (payload) => {\n if (payload.jobExecutionId !== jobExecutionId) return;\n signals.claimed ??= payload;\n });\n}\n\nasync function waitForJobExecutionSignal(\n signals: JobExecutionSignals,\n deadline: number,\n includeClaim: boolean,\n): Promise<void> {\n await condition(\n () =>\n signals.finished !== undefined ||\n signals.leaseExpired ||\n (includeClaim && signals.claimed !== undefined),\n remainingMs(deadline) ?? 0,\n );\n}\n\ninterface JobExecutionResolution {\n input: JobExecutionOrchestrationInput;\n runningVersion: number;\n}\n\nasync function resolveFinishedJobExecution({\n input,\n runningVersion,\n status,\n}: JobExecutionResolution & {\n status: RuntimeCompletionStatus;\n}): Promise<JobExecutionOrchestrationResult> {\n await setJobExecutionStatus({\n jobExecutionId: input.jobExecutionId,\n status: jobExecutionStatusForRuntimeStatus(status),\n version: runningVersion,\n statusReason: status === 'failed' ? 'step_failed' : null,\n });\n if (input.resolveJobStatus === false) {\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'finished',\n status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return {status, jobVersion: input.jobVersion};\n }\n const resolved = await resolveJobStatusOrFailClosed(input);\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'finished',\n status: resolved.status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return resolved;\n}\n\nfunction jobExecutionStatusForRuntimeStatus(\n status: RuntimeCompletionStatus,\n): 'succeeded' | 'failed' | 'cancelled' {\n if (status === 'succeeded' || status === 'failed' || status === 'cancelled') return status;\n throw ApplicationFailure.nonRetryable(\n `Job execution cannot be marked ${status}`,\n 'InvalidJobExecutionStatusError',\n );\n}\n\nasync function resolveLeaseExpiredJobExecution({\n input,\n runningVersion,\n}: JobExecutionResolution): Promise<JobExecutionOrchestrationResult> {\n const leaseExpired = await resolveLeaseExpiredJobExecutionActivity({\n jobExecutionId: input.jobExecutionId,\n expectedVersion: runningVersion,\n });\n if (input.resolveJobStatus === false) {\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'lease_expired',\n status: leaseExpired.status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return {status: leaseExpired.status, jobVersion: input.jobVersion};\n }\n const {status, jobVersion} = await resolveJobStatusOrFailClosed(input);\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'lease_expired',\n status,\n });\n await releaseLeaseBestEffort(input.jobExecutionId);\n return {status, jobVersion};\n}\n\n// Timeout backstop. The activity atomically fails the execution, marks\n// `timed_out_at`, and enqueues WORKFLOWS_JOB_EXECUTION_TIMED_OUT; the runners subscriber\n// then asks the runner to cancel. The lease is intentionally NOT released here.\nasync function resolveTimedOutJobExecution({\n input,\n runningVersion,\n}: JobExecutionResolution): Promise<JobExecutionOrchestrationResult> {\n await failJobExecutionAsTimedOutActivity({\n jobExecutionId: input.jobExecutionId,\n runAttemptId: input.runAttemptId,\n expectedVersion: runningVersion,\n });\n await bulkSetStepStatuses({jobExecutionId: input.jobExecutionId, status: 'failed'});\n if (input.resolveJobStatus === false) {\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'max_duration',\n status: 'failed',\n });\n return {status: 'failed', jobVersion: input.jobVersion};\n }\n const {jobVersion} = await resolveJobStatusOrFailClosed(input);\n log.info('job execution terminated', {\n jobId: input.jobId,\n jobExecutionId: input.jobExecutionId,\n terminationReason: 'max_duration',\n status: 'failed',\n });\n return {status: 'failed', jobVersion};\n}\n\nexport async function jobExecutionOrchestration(\n input: JobExecutionOrchestrationInput,\n): Promise<JobExecutionOrchestrationResult> {\n const signals: JobExecutionSignals = {\n finished: undefined,\n leaseExpired: false,\n claimed: undefined,\n };\n // Register every signal before enqueue can block or publish a claim/outcome event. The\n // handlers retain signals that arrive while the enqueue activity is in flight.\n registerJobExecutionSignalHandlers(input.jobExecutionId, signals);\n await enqueueJobExecution(input);\n\n const timeoutMs = input.executionTimeoutMs ?? DEFAULT_EXECUTION_MAX_DURATION_MS;\n const deadline = Date.now() + timeoutMs;\n await waitForJobExecutionSignal(signals, deadline, true);\n\n // A terminal fact wins over claim even when both signals arrive before the condition\n // resumes. This prevents a late claim from reopening an execution that already finished.\n let resolution = resolveJobExecutionOutcomeSignal(signals);\n if (resolution === 'finished') {\n const {finished} = signals;\n if (finished === undefined) throw new Error('Missing finished signal for finished resolution');\n\n return resolveFinishedJobExecution({\n input,\n runningVersion: input.executionVersion,\n status: finished.status,\n });\n }\n if (resolution === 'lease-expired') {\n return resolveLeaseExpiredJobExecution({input, runningVersion: input.executionVersion});\n }\n if (!signals.claimed) {\n return resolveTimedOutJobExecution({input, runningVersion: input.executionVersion});\n }\n\n const running = await markJobExecutionRunning(input);\n if (running.kind === 'terminal') {\n if (input.resolveJobStatus === false) {\n return {status: running.result.status, jobVersion: input.jobVersion};\n }\n return running.result;\n }\n const {runningVersion} = running;\n\n await waitForJobExecutionSignal(signals, deadline, false);\n resolution = resolveJobExecutionOutcomeSignal(signals);\n if (resolution === 'finished') {\n const {finished} = signals;\n if (finished === undefined) throw new Error('Missing finished signal for finished resolution');\n return resolveFinishedJobExecution({input, runningVersion, status: finished.status});\n }\n if (resolution === 'lease-expired') {\n return resolveLeaseExpiredJobExecution({input, runningVersion});\n }\n return resolveTimedOutJobExecution({input, runningVersion});\n}\n"],"names":["ApplicationFailure","condition","defineSignal","log","proxyActivities","setHandler","hasNoRequiredRunnerLabels","jobExecutionStartOutcome","resolveJobExecutionOutcomeSignal","JOB_CLAIMED_SIGNAL","JOB_FINISHED_SIGNAL","JOB_LEASE_EXPIRED_SIGNAL","remainingMs","setJobStatus","setJobExecutionStatus","enqueueJobExecutionForRunner","bulkSetStepStatuses","failJobExecutionAsTimedOutActivity","resolveLeaseExpiredJobExecutionActivity","startToCloseTimeout","resolveJobStatusFromJobExecutionsActivity","retry","maximumAttempts","releaseLeaseActivity","DEFAULT_EXECUTION_MAX_DURATION_MS","jobFinishedSignal","jobLeaseExpiredSignal","jobClaimedSignal","releaseLeaseBestEffort","jobExecutionId","err","warn","error","String","resolveJobStatusOrFailClosed","input","jobId","newVersion","status","version","jobVersion","statusReason","enqueueJobExecution","requiredLabels","nonRetryable","workspaceId","workflowRunId","runAttemptId","projectId","markJobExecutionRunning","runningVersion","executionVersion","start","kind","registerJobExecutionSignalHandlers","signals","payload","undefined","finished","leaseExpired","claimed","waitForJobExecutionSignal","deadline","includeClaim","resolveFinishedJobExecution","jobExecutionStatusForRuntimeStatus","resolveJobStatus","info","terminationReason","resolved","resolveLeaseExpiredJobExecution","expectedVersion","resolveTimedOutJobExecution","jobExecutionOrchestration","timeoutMs","executionTimeoutMs","Date","now","resolution","Error","running","result"],"mappings":"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"}
@@ -14,8 +14,12 @@ export interface TestConfig {
14
14
  enqueueError?: string;
15
15
  /** If true, enqueueJobExecutionForRunner sends two job-finished signals (for dedup testing) */
16
16
  duplicateSignal?: boolean;
17
- /** If true, enqueueJobExecutionForRunner does nothing (no signal for timeout testing) */
17
+ /** If true, enqueueJobExecutionForRunner does nothing without a signal for timeout testing */
18
18
  skipSignal?: boolean;
19
+ /** If true, emit the claim but hold back the terminal outcome (for deadline testing) */
20
+ skipOutcomeSignal?: boolean;
21
+ /** Runner-owned claim timestamp used by the mock claim event */
22
+ claimedAt?: string;
19
23
  /** If true, signal job-lease-expired instead of job-finished */
20
24
  signalLeaseExpired?: boolean;
21
25
  /** If true, signal BOTH job-finished and job-lease-expired (precedence testing) */
@@ -1 +1 @@
1
- {"version":3,"file":"test-env.d.ts","sourceRoot":"","sources":["../../../src/temporal/workflows/test-env.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-env.d.ts","sourceRoot":"","sources":["../../../src/temporal/workflows/test-env.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,uBAAuB,EAAC,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAC,MAAM,EAAC,MAAM,oBAAoB,CAAC;AAC1C,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,0CAA0C,CAAC;AACtF,OAAO,KAAK,EAAC,qBAAqB,EAAC,MAAM,cAAc,CAAC;AACxD,OAAO,KAAK,EACV,yBAAyB,EACzB,yBAAyB,EACzB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAC,MAAM,EAAC,MAAM,2CAA2C,CAAC;AAGtE,QAAA,MAAM,UAAU,uBAAuB,CAAC;AAGxC,OAAO,EAAC,UAAU,EAAC,CAAC;AAOpB,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,uBAAuB,CAAC,CAAC;IACjD,6FAA6F;IAC7F,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+FAA+F;IAC/F,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,8FAA8F;IAC9F,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wFAAwF;IACxF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gEAAgE;IAChE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,mFAAmF;IACnF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,uBAAuB,CAAC;IAC7C,iFAAiF;IACjF,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8FAA8F;IAC9F,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,2EAA2E;IAC3E,mBAAmB,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC;IACzD,yFAAyF;IACzF,+BAA+B,CAAC,EAAE,MAAM,CAAC;IACzC,gFAAgF;IAChF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,+DAA+D;IAC/D,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,sFAAsF;IACtF,iBAAiB,CAAC,EAAE,yBAAyB,CAAC;IAC9C,8FAA8F;IAC9F,YAAY,CAAC,EAAE,yBAAyB,EAAE,CAAC;IAC3C,gGAAgG;IAChG,WAAW,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACnC,4EAA4E;IAC5E,gBAAgB,CAAC,EAAE;QAAC,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAC,CAAC;CACzE;AAED,eAAO,IAAI,GAAG,EAAE,UAAU,CAAC;AAE3B,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAE9C;AAGD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,eAAO,IAAI,KAAK,EAAE,YAAY,EAAE,CAAC;AAejC,wBAAgB,UAAU,IAAI,IAAI,CAIjC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE,CAEvD;AAED,wBAAgB,wBAAwB,IACM,KAAK,CAAC;IAChD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAC,YAAY,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAC,CAAC;CACjE,CAAC,CACH;AAED,wBAAgB,iBAAiB,IACM,KAAK,CAAC;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAC,CAAC;CACxF,CAAC,CACH;AAED,wBAAgB,uBAAuB,IACS,KAAK,CAAC;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAC,CAAC;CACjG,CAAC,CACH;AAED,wBAAgB,0BAA0B,IACoB,KAAK,CAAC;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAC,OAAO,EAAE,WAAW,GAAG,QAAQ,GAAG,WAAW,CAAA;KAAC,CAAC;CACzD,CAAC,CACH;AAED,wBAAgB,uBAAuB,IACc,KAAK,CAAC;IACvD,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAC,CAAC;CACzC,CAAC,CACH;AAED,wBAAgB,mBAAmB,IAC0B,KAAK,CAAC;IAC/D,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,QAAQ,GAAG,WAAW,CAAA;KAAC,CAAC;CAClE,CAAC,CACH;AAMD,wBAAgB,MAAM,CACpB,EAAE,EAAE,MAAM,EACV,GAAG,EAAE,MAAM,EACX,IAAI,GAAE,MAAM,EAAO,EACnB,OAAO,GAAE;IACP,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,GAAG,SAAS,CAAC;IACtD,sBAAsB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACzC,GACL,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAiBxB;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,aAAa,SAAU,GAAG,MAAM,CAU7E;AAMD,eAAO,IAAI,OAAO,EAAE,uBAAuB,CAAC;AAC5C,eAAO,IAAI,MAAM,EAAE,MAAM,CAAC;AAI1B,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAe9C;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAIjD"}
@@ -1,7 +1,7 @@
1
1
  import { resolve } from 'node:path';
2
2
  import { TestWorkflowEnvironment } from '@temporalio/testing';
3
3
  import { Worker } from '@temporalio/worker';
4
- import { JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL } from '../constants.js';
4
+ import { JOB_CLAIMED_SIGNAL, JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL } from '../constants.js';
5
5
  const TASK_QUEUE = 'test-orchestration';
6
6
  const WORKFLOWS_PATH = resolve(import.meta.dirname, '../../../dist/temporal/workflows/index.js');
7
7
  export { TASK_QUEUE };
@@ -11,12 +11,14 @@ export function setCfg(value) {
11
11
  }
12
12
  export let calls;
13
13
  let versionSeq;
14
+ const pendingJobOutcomes = new Map();
14
15
  function nextVersion() {
15
16
  return ++versionSeq;
16
17
  }
17
18
  export function resetCalls() {
18
19
  calls = [];
19
20
  versionSeq = 0;
21
+ pendingJobOutcomes.clear();
20
22
  }
21
23
  export function callsNamed(name) {
22
24
  return calls.filter((c)=>c.name === name);
@@ -90,7 +92,7 @@ export async function setupEnv() {
90
92
  workflowsPath: WORKFLOWS_PATH,
91
93
  activities: createMockActivities()
92
94
  });
93
- // Run worker in background it processes tasks until shutdown is called
95
+ // Run worker in background: it processes tasks until shutdown is called
94
96
  workerRunPromise = worker.run();
95
97
  workerRunPromise.catch(()=>{
96
98
  // Suppress unhandled rejection on shutdown
@@ -145,12 +147,28 @@ function createMockActivities() {
145
147
  };
146
148
  });
147
149
  },
148
- setJobExecutionStatus: (params)=>{
150
+ setJobExecutionStatus: async (params)=>{
149
151
  calls.push({
150
152
  name: 'setJobExecutionStatus',
151
153
  params
152
154
  });
153
155
  const status = params.status === 'running' && cfg.runningJobStatus ? cfg.runningJobStatus : params.status;
156
+ if (params.status === 'running') {
157
+ const outcome = pendingJobOutcomes.get(params.jobExecutionId);
158
+ pendingJobOutcomes.delete(params.jobExecutionId);
159
+ if (outcome && status === 'running') {
160
+ await outcome.handle.signal(JOB_FINISHED_SIGNAL, {
161
+ status: outcome.status,
162
+ jobExecutionId: params.jobExecutionId
163
+ });
164
+ if (outcome.duplicateSignal) {
165
+ await outcome.handle.signal(JOB_FINISHED_SIGNAL, {
166
+ status: 'failed',
167
+ jobExecutionId: params.jobExecutionId
168
+ });
169
+ }
170
+ }
171
+ }
154
172
  return {
155
173
  newVersion: nextVersion(),
156
174
  status
@@ -183,6 +201,11 @@ function createMockActivities() {
183
201
  if (cfg.skipSignal) return;
184
202
  const status = cfg.jobResults.get(params.jobId) ?? 'succeeded';
185
203
  const handle = testEnv.client.workflow.getHandle(`job:${params.jobId}`);
204
+ await handle.signal(JOB_CLAIMED_SIGNAL, {
205
+ jobExecutionId: params.jobExecutionId,
206
+ claimedAt: cfg.claimedAt ?? '2026-06-22T10:05:00.000Z'
207
+ });
208
+ if (cfg.skipOutcomeSignal) return;
186
209
  if (cfg.signalLeaseExpired) {
187
210
  await handle.signal(JOB_LEASE_EXPIRED_SIGNAL, {
188
211
  jobExecutionId: params.jobExecutionId
@@ -199,16 +222,14 @@ function createMockActivities() {
199
222
  });
200
223
  return;
201
224
  }
202
- await handle.signal(JOB_FINISHED_SIGNAL, {
225
+ // The terminal outbox is independent from the claim, but the mock delivers it from the
226
+ // pending → running activity. This gives the workflow a deterministic ordering boundary
227
+ // without leaving a polling promise alive after the test finishes.
228
+ pendingJobOutcomes.set(params.jobExecutionId, {
229
+ handle,
203
230
  status,
204
- jobExecutionId: params.jobExecutionId
231
+ duplicateSignal: cfg.duplicateSignal ?? false
205
232
  });
206
- if (cfg.duplicateSignal) {
207
- await handle.signal(JOB_FINISHED_SIGNAL, {
208
- status: 'failed',
209
- jobExecutionId: params.jobExecutionId
210
- });
211
- }
212
233
  },
213
234
  resolveLeaseExpiredJobExecutionActivity: (params)=>{
214
235
  calls.push({
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/temporal/workflows/test-env.ts"],"sourcesContent":["import {resolve} from 'node:path';\nimport {TestWorkflowEnvironment} from '@temporalio/testing';\nimport {Worker} from '@temporalio/worker';\nimport type {RuntimeCompletionStatus} from '#core/workflow-scheduling/runtime-dag.js';\nimport type {JobActivationDecision} from '#db/index.js';\nimport type {\n ActivateJobListenerResult,\n DrainListenerEventsResult,\n ListenerBufferPeek,\n} from '#db/job-listeners.js';\nimport type {RunDag} from '../activities/orchestration-activities.js';\nimport {JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL} from '../constants.js';\n\nconst TASK_QUEUE = 'test-orchestration';\nconst WORKFLOWS_PATH = resolve(import.meta.dirname, '../../../dist/temporal/workflows/index.js');\n\nexport {TASK_QUEUE};\n\n// ---------------------------------------------------------------------------\n// Shared mutable test config — each test sets this before starting a workflow.\n// Activities read from it via closure. Tests run serially within a describe.\n// ---------------------------------------------------------------------------\n\nexport interface TestConfig {\n dag: RunDag;\n /** Map of jobId → status the mock runner should signal back */\n jobResults: Map<string, RuntimeCompletionStatus>;\n /** If set, enqueueJobExecutionForRunner will throw with this message instead of signaling */\n enqueueError?: string;\n /** If true, enqueueJobExecutionForRunner sends two job-finished signals (for dedup testing) */\n duplicateSignal?: boolean;\n /** If true, enqueueJobExecutionForRunner does nothing (no signal — for timeout testing) */\n skipSignal?: boolean;\n /** If true, signal job-lease-expired instead of job-finished */\n signalLeaseExpired?: boolean;\n /** If true, signal BOTH job-finished and job-lease-expired (precedence testing) */\n signalBoth?: boolean;\n /** Status resolveLeaseExpiredJobExecutionActivity returns (defaults to 'failed') */\n leaseExpiredStatus?: RuntimeCompletionStatus;\n /** If set, resolveJobStatusFromJobExecutionsActivity throws with this message */\n resolveJobStatusError?: string;\n /** If set, releaseLeaseActivity throws (non-retryable) to prove the workflow still returns */\n releaseLeaseError?: string;\n /** Scripted job activation decisions keyed by job id; defaults to start */\n activationDecisions?: Map<string, JobActivationDecision>;\n /** If set, failJobExecutionAsTimedOutActivity throws (for timeout error-path testing) */\n failJobExecutionAsTimedOutError?: string;\n /** Effective status returned by the initial running setRunAttemptStatus call */\n initialRunStatus?: string;\n /** Effective status returned by a running setJobStatus call */\n runningJobStatus?: string;\n /** Result returned by activateJobListenerActivity (defaults to a running listener) */\n listenerActivated?: ActivateJobListenerResult;\n /** Scripted drain results consumed in order; once exhausted, drain returns {kind: 'empty'} */\n drainResults?: DrainListenerEventsResult[];\n /** Scripted listener buffer peeks consumed in order; once exhausted, returns an empty buffer */\n peekResults?: ListenerBufferPeek[];\n /** Result returned by resolveJobListenerActivity (defaults to succeeded) */\n listenerResolved?: {status: 'succeeded' | 'failed'; jobVersion: number};\n}\n\nexport let cfg: TestConfig;\n\nexport function setCfg(value: TestConfig): void {\n cfg = value;\n}\n\n// Track every activity call for assertions\nexport interface ActivityCall {\n name: string;\n params: unknown;\n}\n\nexport let calls: ActivityCall[];\nlet versionSeq: number;\n\nfunction nextVersion(): number {\n return ++versionSeq;\n}\n\nexport function resetCalls(): void {\n calls = [];\n versionSeq = 0;\n}\n\nexport function callsNamed(name: string): ActivityCall[] {\n return calls.filter((c) => c.name === name);\n}\n\nexport function setRunAttemptStatusCalls() {\n return callsNamed('setRunAttemptStatus') as Array<{\n name: string;\n params: {runAttemptId: string; status: string; version: number};\n }>;\n}\n\nexport function setJobStatusCalls() {\n return callsNamed('setJobStatus') as Array<{\n name: string;\n params: {jobId: string; status: string; version: number; statusReason?: string | null};\n }>;\n}\n\nexport function setExecutionStatusCalls() {\n return callsNamed('setJobExecutionStatus') as Array<{\n name: string;\n params: {jobExecutionId: string; status: string; version: number; statusReason?: string | null};\n }>;\n}\n\nexport function listenerFiringOutcomeCalls() {\n return callsNamed('recordListenerFiringOutcomeActivity') as Array<{\n name: string;\n params: {outcome: 'succeeded' | 'failed' | 'cancelled'};\n }>;\n}\n\nexport function resolveJobListenerCalls() {\n return callsNamed('resolveJobListenerActivity') as Array<{\n name: string;\n params: {jobId: string; reason: string};\n }>;\n}\n\nexport function settleListenerCalls() {\n return callsNamed('settleListenerJobExecutionActivity') as Array<{\n name: string;\n params: {jobExecutionId: string; status: 'failed' | 'cancelled'};\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// DAG helpers\n// ---------------------------------------------------------------------------\n\nexport function dagJob(\n id: string,\n key: string,\n deps: string[] = [],\n options: {\n mode?: RunDag['jobs'][number]['mode'] | undefined;\n status?: RunDag['jobs'][number]['status'] | undefined;\n hasActivationCondition?: boolean | undefined;\n } = {},\n): RunDag['jobs'][number] {\n const mode = options.mode ?? 'one_shot';\n return {\n id,\n key,\n mode,\n status: options.status ?? 'pending',\n ...(mode === 'listening' ? {} : {jobExecutionId: id, executionVersion: 1}),\n executionTimeoutMs: null,\n listeningTimeoutMs: null,\n maxExecutions: null,\n onResolve: null,\n hasActivationCondition: options.hasActivationCondition ?? false,\n dependencies: deps,\n runner: ['ubuntu22'],\n version: 1,\n };\n}\n\nexport function makeDag(jobs: RunDag['jobs'], workflowRunId = 'run-1'): RunDag {\n return {\n workflowRunId,\n runAttemptId: `${workflowRunId}-attempt-1`,\n workspaceId: 'workspace-1',\n projectId: 'project-1',\n runVersion: 1,\n runTimeoutMs: 30 * 24 * 60 * 60 * 1000,\n jobs,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Environment lifecycle\n// ---------------------------------------------------------------------------\n\nexport let testEnv: TestWorkflowEnvironment;\nexport let worker: Worker;\n\nlet workerRunPromise: Promise<void> | undefined;\n\nexport async function setupEnv(): Promise<void> {\n testEnv = await TestWorkflowEnvironment.createLocal();\n\n worker = await Worker.create({\n connection: testEnv.nativeConnection,\n taskQueue: TASK_QUEUE,\n workflowsPath: WORKFLOWS_PATH,\n activities: createMockActivities(),\n });\n\n // Run worker in background — it processes tasks until shutdown is called\n workerRunPromise = worker.run();\n workerRunPromise.catch(() => {\n // Suppress unhandled rejection on shutdown\n });\n}\n\nexport async function teardownEnv(): Promise<void> {\n worker?.shutdown();\n await workerRunPromise;\n await testEnv?.teardown();\n}\n\nfunction createMockActivities() {\n return {\n loadRunAttemptDag: (runAttemptId: string): RunDag => {\n calls.push({name: 'loadRunAttemptDag', params: runAttemptId});\n return cfg.dag;\n },\n\n setRunAttemptStatus: (params: {runAttemptId: string; status: string; version: number}) => {\n calls.push({name: 'setRunAttemptStatus', params});\n const status =\n params.status === 'running' && cfg.initialRunStatus ? cfg.initialRunStatus : params.status;\n return {newVersion: nextVersion(), status};\n },\n\n setJobStatus: (params: {\n jobId: string;\n status: string;\n version: number;\n statusReason?: string | null;\n }) => {\n calls.push({name: 'setJobStatus', params});\n const status =\n params.status === 'running' && cfg.runningJobStatus ? cfg.runningJobStatus : params.status;\n return {newVersion: nextVersion(), status};\n },\n\n evaluateJobActivationsActivity: (params: {\n runAttemptId: string;\n jobs: readonly {jobId: string; expectedVersion: number}[];\n }): JobActivationDecision[] => {\n calls.push({name: 'evaluateJobActivationsActivity', params});\n return params.jobs.map((job) => {\n const decision = cfg.activationDecisions?.get(job.jobId);\n return decision ?? {kind: 'start-job', jobId: job.jobId};\n });\n },\n\n setJobExecutionStatus: (params: {\n jobExecutionId: string;\n status: string;\n version: number;\n statusReason?: string | null;\n }) => {\n calls.push({name: 'setJobExecutionStatus', params});\n const status =\n params.status === 'running' && cfg.runningJobStatus ? cfg.runningJobStatus : params.status;\n return {newVersion: nextVersion(), status};\n },\n\n bulkSetStepStatuses: (params: {jobExecutionId: string; status: string}) => {\n calls.push({name: 'bulkSetStepStatuses', params});\n },\n\n cancelRunnerJobsActivity: (params: {jobIds: string[]}) => {\n calls.push({name: 'cancelRunnerJobsActivity', params});\n },\n\n // Scheduling is step-less. The mock runner reports the job outcome by signalling\n // the per-step terminal-completion signal (job-finished) and/or the lease-expiry\n // signal, reproducing the outbox → subscriber → signal rail.\n enqueueJobExecutionForRunner: async (params: {\n workspaceId: string;\n workflowRunId: string;\n runAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n }) => {\n calls.push({name: 'enqueueJobExecutionForRunner', params});\n\n if (cfg.enqueueError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.enqueueError);\n }\n\n if (cfg.skipSignal) return;\n\n const status = cfg.jobResults.get(params.jobId) ?? 'succeeded';\n const handle = testEnv.client.workflow.getHandle(`job:${params.jobId}`);\n\n if (cfg.signalLeaseExpired) {\n await handle.signal(JOB_LEASE_EXPIRED_SIGNAL, {jobExecutionId: params.jobExecutionId});\n return;\n }\n\n if (cfg.signalBoth) {\n await handle.signal(JOB_FINISHED_SIGNAL, {status, jobExecutionId: params.jobExecutionId});\n await handle.signal(JOB_LEASE_EXPIRED_SIGNAL, {jobExecutionId: params.jobExecutionId});\n return;\n }\n\n await handle.signal(JOB_FINISHED_SIGNAL, {status, jobExecutionId: params.jobExecutionId});\n\n if (cfg.duplicateSignal) {\n await handle.signal(JOB_FINISHED_SIGNAL, {\n status: 'failed',\n jobExecutionId: params.jobExecutionId,\n });\n }\n },\n\n resolveLeaseExpiredJobExecutionActivity: (params: {\n jobExecutionId: string;\n expectedVersion: number;\n }) => {\n calls.push({name: 'resolveLeaseExpiredJobExecutionActivity', params});\n return {status: cfg.leaseExpiredStatus ?? 'failed', executionVersion: nextVersion()};\n },\n\n resolveJobStatusFromJobExecutionsActivity: async (params: {jobId: string}) => {\n calls.push({name: 'resolveJobStatusFromJobExecutionsActivity', params});\n if (cfg.resolveJobStatusError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.resolveJobStatusError);\n }\n const terminalExecutionStatus = [...setExecutionStatusCalls()]\n .reverse()\n .find(\n (call) => call.params.jobExecutionId === params.jobId && call.params.status !== 'running',\n )?.params.status as RuntimeCompletionStatus | undefined;\n return {\n status: cfg.leaseExpiredStatus ?? terminalExecutionStatus ?? 'succeeded',\n jobVersion: nextVersion(),\n };\n },\n\n releaseLeaseActivity: async (params: {jobExecutionId: string}) => {\n calls.push({name: 'releaseLeaseActivity', params});\n if (cfg.releaseLeaseError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.releaseLeaseError);\n }\n },\n\n failJobExecutionAsTimedOutActivity: async (params: {\n jobExecutionId: string;\n runAttemptId: string;\n expectedVersion: number;\n }) => {\n calls.push({name: 'failJobExecutionAsTimedOutActivity', params});\n if (cfg.failJobExecutionAsTimedOutError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.failJobExecutionAsTimedOutError);\n }\n return {newVersion: nextVersion()};\n },\n\n activateJobListenerActivity: (params: {jobId: string; expectedVersion: number}) => {\n calls.push({name: 'activateJobListenerActivity', params});\n return (\n cfg.listenerActivated ?? {\n status: 'running',\n jobStatus: 'running',\n jobVersion: nextVersion(),\n executionCount: 0,\n }\n );\n },\n\n // Each call consumes the next scripted drain result. An exhausted script means\n // \"no events buffered\", which parks the listener until a signal or its deadline.\n drainListenerEventsActivity: (params: {\n jobId: string;\n expectedSequence: number;\n maxSize?: number;\n }) => {\n calls.push({name: 'drainListenerEventsActivity', params});\n return cfg.drainResults?.shift() ?? {kind: 'empty'};\n },\n\n peekListenerBufferActivity: (params: {jobId: string}) => {\n calls.push({name: 'peekListenerBufferActivity', params});\n return (\n cfg.peekResults?.shift() ?? {\n fireCount: 0,\n resolvePending: false,\n oldestAgeMs: 0,\n newestAgeMs: 0,\n }\n );\n },\n\n resolveJobListenerActivity: (params: {jobId: string; reason: string}) => {\n calls.push({name: 'resolveJobListenerActivity', params});\n return cfg.listenerResolved ?? {status: 'succeeded', jobVersion: nextVersion()};\n },\n\n settleListenerJobExecutionActivity: (params: {\n jobExecutionId: string;\n status: 'failed' | 'cancelled';\n }) => {\n calls.push({name: 'settleListenerJobExecutionActivity', params});\n },\n\n recordListenerFiringOutcomeActivity: (params: {\n outcome: 'succeeded' | 'failed' | 'cancelled';\n }) => {\n calls.push({name: 'recordListenerFiringOutcomeActivity', params});\n },\n };\n}\n"],"names":["resolve","TestWorkflowEnvironment","Worker","JOB_FINISHED_SIGNAL","JOB_LEASE_EXPIRED_SIGNAL","TASK_QUEUE","WORKFLOWS_PATH","dirname","cfg","setCfg","value","calls","versionSeq","nextVersion","resetCalls","callsNamed","name","filter","c","setRunAttemptStatusCalls","setJobStatusCalls","setExecutionStatusCalls","listenerFiringOutcomeCalls","resolveJobListenerCalls","settleListenerCalls","dagJob","id","key","deps","options","mode","status","jobExecutionId","executionVersion","executionTimeoutMs","listeningTimeoutMs","maxExecutions","onResolve","hasActivationCondition","dependencies","runner","version","makeDag","jobs","workflowRunId","runAttemptId","workspaceId","projectId","runVersion","runTimeoutMs","testEnv","worker","workerRunPromise","setupEnv","createLocal","create","connection","nativeConnection","taskQueue","workflowsPath","activities","createMockActivities","run","catch","teardownEnv","shutdown","teardown","loadRunAttemptDag","push","params","dag","setRunAttemptStatus","initialRunStatus","newVersion","setJobStatus","runningJobStatus","evaluateJobActivationsActivity","map","job","decision","activationDecisions","get","jobId","kind","setJobExecutionStatus","bulkSetStepStatuses","cancelRunnerJobsActivity","enqueueJobExecutionForRunner","enqueueError","ApplicationFailure","nonRetryable","skipSignal","jobResults","handle","client","workflow","getHandle","signalLeaseExpired","signal","signalBoth","duplicateSignal","resolveLeaseExpiredJobExecutionActivity","leaseExpiredStatus","resolveJobStatusFromJobExecutionsActivity","resolveJobStatusError","terminalExecutionStatus","reverse","find","call","jobVersion","releaseLeaseActivity","releaseLeaseError","failJobExecutionAsTimedOutActivity","failJobExecutionAsTimedOutError","activateJobListenerActivity","listenerActivated","jobStatus","executionCount","drainListenerEventsActivity","drainResults","shift","peekListenerBufferActivity","peekResults","fireCount","resolvePending","oldestAgeMs","newestAgeMs","resolveJobListenerActivity","listenerResolved","settleListenerJobExecutionActivity","recordListenerFiringOutcomeActivity"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../src/temporal/workflows/test-env.ts"],"sourcesContent":["import {resolve} from 'node:path';\nimport {TestWorkflowEnvironment} from '@temporalio/testing';\nimport {Worker} from '@temporalio/worker';\nimport type {RuntimeCompletionStatus} from '#core/workflow-scheduling/runtime-dag.js';\nimport type {JobActivationDecision} from '#db/index.js';\nimport type {\n ActivateJobListenerResult,\n DrainListenerEventsResult,\n ListenerBufferPeek,\n} from '#db/job-listeners.js';\nimport type {RunDag} from '../activities/orchestration-activities.js';\nimport {JOB_CLAIMED_SIGNAL, JOB_FINISHED_SIGNAL, JOB_LEASE_EXPIRED_SIGNAL} from '../constants.js';\n\nconst TASK_QUEUE = 'test-orchestration';\nconst WORKFLOWS_PATH = resolve(import.meta.dirname, '../../../dist/temporal/workflows/index.js');\n\nexport {TASK_QUEUE};\n\n// ---------------------------------------------------------------------------\n// Shared mutable test config: each test sets this before starting a workflow.\n// Activities read from it via closure. Tests run serially within a describe.\n// ---------------------------------------------------------------------------\n\nexport interface TestConfig {\n dag: RunDag;\n /** Map of jobId → status the mock runner should signal back */\n jobResults: Map<string, RuntimeCompletionStatus>;\n /** If set, enqueueJobExecutionForRunner will throw with this message instead of signaling */\n enqueueError?: string;\n /** If true, enqueueJobExecutionForRunner sends two job-finished signals (for dedup testing) */\n duplicateSignal?: boolean;\n /** If true, enqueueJobExecutionForRunner does nothing without a signal for timeout testing */\n skipSignal?: boolean;\n /** If true, emit the claim but hold back the terminal outcome (for deadline testing) */\n skipOutcomeSignal?: boolean;\n /** Runner-owned claim timestamp used by the mock claim event */\n claimedAt?: string;\n /** If true, signal job-lease-expired instead of job-finished */\n signalLeaseExpired?: boolean;\n /** If true, signal BOTH job-finished and job-lease-expired (precedence testing) */\n signalBoth?: boolean;\n /** Status resolveLeaseExpiredJobExecutionActivity returns (defaults to 'failed') */\n leaseExpiredStatus?: RuntimeCompletionStatus;\n /** If set, resolveJobStatusFromJobExecutionsActivity throws with this message */\n resolveJobStatusError?: string;\n /** If set, releaseLeaseActivity throws (non-retryable) to prove the workflow still returns */\n releaseLeaseError?: string;\n /** Scripted job activation decisions keyed by job id; defaults to start */\n activationDecisions?: Map<string, JobActivationDecision>;\n /** If set, failJobExecutionAsTimedOutActivity throws (for timeout error-path testing) */\n failJobExecutionAsTimedOutError?: string;\n /** Effective status returned by the initial running setRunAttemptStatus call */\n initialRunStatus?: string;\n /** Effective status returned by a running setJobStatus call */\n runningJobStatus?: string;\n /** Result returned by activateJobListenerActivity (defaults to a running listener) */\n listenerActivated?: ActivateJobListenerResult;\n /** Scripted drain results consumed in order; once exhausted, drain returns {kind: 'empty'} */\n drainResults?: DrainListenerEventsResult[];\n /** Scripted listener buffer peeks consumed in order; once exhausted, returns an empty buffer */\n peekResults?: ListenerBufferPeek[];\n /** Result returned by resolveJobListenerActivity (defaults to succeeded) */\n listenerResolved?: {status: 'succeeded' | 'failed'; jobVersion: number};\n}\n\nexport let cfg: TestConfig;\n\nexport function setCfg(value: TestConfig): void {\n cfg = value;\n}\n\n// Track every activity call for assertions\nexport interface ActivityCall {\n name: string;\n params: unknown;\n}\n\nexport let calls: ActivityCall[];\nlet versionSeq: number;\nconst pendingJobOutcomes = new Map<\n string,\n {\n handle: ReturnType<typeof testEnv.client.workflow.getHandle>;\n status: RuntimeCompletionStatus;\n duplicateSignal: boolean;\n }\n>();\n\nfunction nextVersion(): number {\n return ++versionSeq;\n}\n\nexport function resetCalls(): void {\n calls = [];\n versionSeq = 0;\n pendingJobOutcomes.clear();\n}\n\nexport function callsNamed(name: string): ActivityCall[] {\n return calls.filter((c) => c.name === name);\n}\n\nexport function setRunAttemptStatusCalls() {\n return callsNamed('setRunAttemptStatus') as Array<{\n name: string;\n params: {runAttemptId: string; status: string; version: number};\n }>;\n}\n\nexport function setJobStatusCalls() {\n return callsNamed('setJobStatus') as Array<{\n name: string;\n params: {jobId: string; status: string; version: number; statusReason?: string | null};\n }>;\n}\n\nexport function setExecutionStatusCalls() {\n return callsNamed('setJobExecutionStatus') as Array<{\n name: string;\n params: {jobExecutionId: string; status: string; version: number; statusReason?: string | null};\n }>;\n}\n\nexport function listenerFiringOutcomeCalls() {\n return callsNamed('recordListenerFiringOutcomeActivity') as Array<{\n name: string;\n params: {outcome: 'succeeded' | 'failed' | 'cancelled'};\n }>;\n}\n\nexport function resolveJobListenerCalls() {\n return callsNamed('resolveJobListenerActivity') as Array<{\n name: string;\n params: {jobId: string; reason: string};\n }>;\n}\n\nexport function settleListenerCalls() {\n return callsNamed('settleListenerJobExecutionActivity') as Array<{\n name: string;\n params: {jobExecutionId: string; status: 'failed' | 'cancelled'};\n }>;\n}\n\n// ---------------------------------------------------------------------------\n// DAG helpers\n// ---------------------------------------------------------------------------\n\nexport function dagJob(\n id: string,\n key: string,\n deps: string[] = [],\n options: {\n mode?: RunDag['jobs'][number]['mode'] | undefined;\n status?: RunDag['jobs'][number]['status'] | undefined;\n hasActivationCondition?: boolean | undefined;\n } = {},\n): RunDag['jobs'][number] {\n const mode = options.mode ?? 'one_shot';\n return {\n id,\n key,\n mode,\n status: options.status ?? 'pending',\n ...(mode === 'listening' ? {} : {jobExecutionId: id, executionVersion: 1}),\n executionTimeoutMs: null,\n listeningTimeoutMs: null,\n maxExecutions: null,\n onResolve: null,\n hasActivationCondition: options.hasActivationCondition ?? false,\n dependencies: deps,\n runner: ['ubuntu22'],\n version: 1,\n };\n}\n\nexport function makeDag(jobs: RunDag['jobs'], workflowRunId = 'run-1'): RunDag {\n return {\n workflowRunId,\n runAttemptId: `${workflowRunId}-attempt-1`,\n workspaceId: 'workspace-1',\n projectId: 'project-1',\n runVersion: 1,\n runTimeoutMs: 30 * 24 * 60 * 60 * 1000,\n jobs,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Environment lifecycle\n// ---------------------------------------------------------------------------\n\nexport let testEnv: TestWorkflowEnvironment;\nexport let worker: Worker;\n\nlet workerRunPromise: Promise<void> | undefined;\n\nexport async function setupEnv(): Promise<void> {\n testEnv = await TestWorkflowEnvironment.createLocal();\n\n worker = await Worker.create({\n connection: testEnv.nativeConnection,\n taskQueue: TASK_QUEUE,\n workflowsPath: WORKFLOWS_PATH,\n activities: createMockActivities(),\n });\n\n // Run worker in background: it processes tasks until shutdown is called\n workerRunPromise = worker.run();\n workerRunPromise.catch(() => {\n // Suppress unhandled rejection on shutdown\n });\n}\n\nexport async function teardownEnv(): Promise<void> {\n worker?.shutdown();\n await workerRunPromise;\n await testEnv?.teardown();\n}\n\nfunction createMockActivities() {\n return {\n loadRunAttemptDag: (runAttemptId: string): RunDag => {\n calls.push({name: 'loadRunAttemptDag', params: runAttemptId});\n return cfg.dag;\n },\n\n setRunAttemptStatus: (params: {runAttemptId: string; status: string; version: number}) => {\n calls.push({name: 'setRunAttemptStatus', params});\n const status =\n params.status === 'running' && cfg.initialRunStatus ? cfg.initialRunStatus : params.status;\n return {newVersion: nextVersion(), status};\n },\n\n setJobStatus: (params: {\n jobId: string;\n status: string;\n version: number;\n statusReason?: string | null;\n }) => {\n calls.push({name: 'setJobStatus', params});\n const status =\n params.status === 'running' && cfg.runningJobStatus ? cfg.runningJobStatus : params.status;\n return {newVersion: nextVersion(), status};\n },\n\n evaluateJobActivationsActivity: (params: {\n runAttemptId: string;\n jobs: readonly {jobId: string; expectedVersion: number}[];\n }): JobActivationDecision[] => {\n calls.push({name: 'evaluateJobActivationsActivity', params});\n return params.jobs.map((job) => {\n const decision = cfg.activationDecisions?.get(job.jobId);\n return decision ?? {kind: 'start-job', jobId: job.jobId};\n });\n },\n\n setJobExecutionStatus: async (params: {\n jobExecutionId: string;\n status: string;\n version: number;\n statusReason?: string | null;\n }) => {\n calls.push({name: 'setJobExecutionStatus', params});\n const status =\n params.status === 'running' && cfg.runningJobStatus ? cfg.runningJobStatus : params.status;\n\n if (params.status === 'running') {\n const outcome = pendingJobOutcomes.get(params.jobExecutionId);\n pendingJobOutcomes.delete(params.jobExecutionId);\n if (outcome && status === 'running') {\n await outcome.handle.signal(JOB_FINISHED_SIGNAL, {\n status: outcome.status,\n jobExecutionId: params.jobExecutionId,\n });\n if (outcome.duplicateSignal) {\n await outcome.handle.signal(JOB_FINISHED_SIGNAL, {\n status: 'failed',\n jobExecutionId: params.jobExecutionId,\n });\n }\n }\n }\n\n return {newVersion: nextVersion(), status};\n },\n\n bulkSetStepStatuses: (params: {jobExecutionId: string; status: string}) => {\n calls.push({name: 'bulkSetStepStatuses', params});\n },\n\n cancelRunnerJobsActivity: (params: {jobIds: string[]}) => {\n calls.push({name: 'cancelRunnerJobsActivity', params});\n },\n\n // Scheduling is step-less. The mock runner reports the job outcome by signalling\n // the per-step terminal-completion signal (job-finished) and/or the lease-expiry\n // signal, reproducing the outbox → subscriber → signal rail.\n enqueueJobExecutionForRunner: async (params: {\n workspaceId: string;\n workflowRunId: string;\n runAttemptId: string;\n jobId: string;\n jobExecutionId: string;\n projectId: string;\n requiredLabels: string[];\n }) => {\n calls.push({name: 'enqueueJobExecutionForRunner', params});\n\n if (cfg.enqueueError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.enqueueError);\n }\n\n if (cfg.skipSignal) return;\n\n const status = cfg.jobResults.get(params.jobId) ?? 'succeeded';\n const handle = testEnv.client.workflow.getHandle(`job:${params.jobId}`);\n await handle.signal(JOB_CLAIMED_SIGNAL, {\n jobExecutionId: params.jobExecutionId,\n claimedAt: cfg.claimedAt ?? '2026-06-22T10:05:00.000Z',\n });\n\n if (cfg.skipOutcomeSignal) return;\n\n if (cfg.signalLeaseExpired) {\n await handle.signal(JOB_LEASE_EXPIRED_SIGNAL, {jobExecutionId: params.jobExecutionId});\n return;\n }\n\n if (cfg.signalBoth) {\n await handle.signal(JOB_FINISHED_SIGNAL, {status, jobExecutionId: params.jobExecutionId});\n await handle.signal(JOB_LEASE_EXPIRED_SIGNAL, {jobExecutionId: params.jobExecutionId});\n return;\n }\n\n // The terminal outbox is independent from the claim, but the mock delivers it from the\n // pending → running activity. This gives the workflow a deterministic ordering boundary\n // without leaving a polling promise alive after the test finishes.\n pendingJobOutcomes.set(params.jobExecutionId, {\n handle,\n status,\n duplicateSignal: cfg.duplicateSignal ?? false,\n });\n },\n\n resolveLeaseExpiredJobExecutionActivity: (params: {\n jobExecutionId: string;\n expectedVersion: number;\n }) => {\n calls.push({name: 'resolveLeaseExpiredJobExecutionActivity', params});\n return {status: cfg.leaseExpiredStatus ?? 'failed', executionVersion: nextVersion()};\n },\n\n resolveJobStatusFromJobExecutionsActivity: async (params: {jobId: string}) => {\n calls.push({name: 'resolveJobStatusFromJobExecutionsActivity', params});\n if (cfg.resolveJobStatusError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.resolveJobStatusError);\n }\n const terminalExecutionStatus = [...setExecutionStatusCalls()]\n .reverse()\n .find(\n (call) => call.params.jobExecutionId === params.jobId && call.params.status !== 'running',\n )?.params.status as RuntimeCompletionStatus | undefined;\n return {\n status: cfg.leaseExpiredStatus ?? terminalExecutionStatus ?? 'succeeded',\n jobVersion: nextVersion(),\n };\n },\n\n releaseLeaseActivity: async (params: {jobExecutionId: string}) => {\n calls.push({name: 'releaseLeaseActivity', params});\n if (cfg.releaseLeaseError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.releaseLeaseError);\n }\n },\n\n failJobExecutionAsTimedOutActivity: async (params: {\n jobExecutionId: string;\n runAttemptId: string;\n expectedVersion: number;\n }) => {\n calls.push({name: 'failJobExecutionAsTimedOutActivity', params});\n if (cfg.failJobExecutionAsTimedOutError) {\n const {ApplicationFailure} = await import('@temporalio/common');\n throw ApplicationFailure.nonRetryable(cfg.failJobExecutionAsTimedOutError);\n }\n return {newVersion: nextVersion()};\n },\n\n activateJobListenerActivity: (params: {jobId: string; expectedVersion: number}) => {\n calls.push({name: 'activateJobListenerActivity', params});\n return (\n cfg.listenerActivated ?? {\n status: 'running',\n jobStatus: 'running',\n jobVersion: nextVersion(),\n executionCount: 0,\n }\n );\n },\n\n // Each call consumes the next scripted drain result. An exhausted script means\n // \"no events buffered\", which parks the listener until a signal or its deadline.\n drainListenerEventsActivity: (params: {\n jobId: string;\n expectedSequence: number;\n maxSize?: number;\n }) => {\n calls.push({name: 'drainListenerEventsActivity', params});\n return cfg.drainResults?.shift() ?? {kind: 'empty'};\n },\n\n peekListenerBufferActivity: (params: {jobId: string}) => {\n calls.push({name: 'peekListenerBufferActivity', params});\n return (\n cfg.peekResults?.shift() ?? {\n fireCount: 0,\n resolvePending: false,\n oldestAgeMs: 0,\n newestAgeMs: 0,\n }\n );\n },\n\n resolveJobListenerActivity: (params: {jobId: string; reason: string}) => {\n calls.push({name: 'resolveJobListenerActivity', params});\n return cfg.listenerResolved ?? {status: 'succeeded', jobVersion: nextVersion()};\n },\n\n settleListenerJobExecutionActivity: (params: {\n jobExecutionId: string;\n status: 'failed' | 'cancelled';\n }) => {\n calls.push({name: 'settleListenerJobExecutionActivity', params});\n },\n\n recordListenerFiringOutcomeActivity: (params: {\n outcome: 'succeeded' | 'failed' | 'cancelled';\n }) => {\n calls.push({name: 'recordListenerFiringOutcomeActivity', params});\n },\n };\n}\n"],"names":["resolve","TestWorkflowEnvironment","Worker","JOB_CLAIMED_SIGNAL","JOB_FINISHED_SIGNAL","JOB_LEASE_EXPIRED_SIGNAL","TASK_QUEUE","WORKFLOWS_PATH","dirname","cfg","setCfg","value","calls","versionSeq","pendingJobOutcomes","Map","nextVersion","resetCalls","clear","callsNamed","name","filter","c","setRunAttemptStatusCalls","setJobStatusCalls","setExecutionStatusCalls","listenerFiringOutcomeCalls","resolveJobListenerCalls","settleListenerCalls","dagJob","id","key","deps","options","mode","status","jobExecutionId","executionVersion","executionTimeoutMs","listeningTimeoutMs","maxExecutions","onResolve","hasActivationCondition","dependencies","runner","version","makeDag","jobs","workflowRunId","runAttemptId","workspaceId","projectId","runVersion","runTimeoutMs","testEnv","worker","workerRunPromise","setupEnv","createLocal","create","connection","nativeConnection","taskQueue","workflowsPath","activities","createMockActivities","run","catch","teardownEnv","shutdown","teardown","loadRunAttemptDag","push","params","dag","setRunAttemptStatus","initialRunStatus","newVersion","setJobStatus","runningJobStatus","evaluateJobActivationsActivity","map","job","decision","activationDecisions","get","jobId","kind","setJobExecutionStatus","outcome","delete","handle","signal","duplicateSignal","bulkSetStepStatuses","cancelRunnerJobsActivity","enqueueJobExecutionForRunner","enqueueError","ApplicationFailure","nonRetryable","skipSignal","jobResults","client","workflow","getHandle","claimedAt","skipOutcomeSignal","signalLeaseExpired","signalBoth","set","resolveLeaseExpiredJobExecutionActivity","leaseExpiredStatus","resolveJobStatusFromJobExecutionsActivity","resolveJobStatusError","terminalExecutionStatus","reverse","find","call","jobVersion","releaseLeaseActivity","releaseLeaseError","failJobExecutionAsTimedOutActivity","failJobExecutionAsTimedOutError","activateJobListenerActivity","listenerActivated","jobStatus","executionCount","drainListenerEventsActivity","drainResults","shift","peekListenerBufferActivity","peekResults","fireCount","resolvePending","oldestAgeMs","newestAgeMs","resolveJobListenerActivity","listenerResolved","settleListenerJobExecutionActivity","recordListenerFiringOutcomeActivity"],"mappings":"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"}