@nest-batch/core 0.2.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 (476) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +368 -0
  3. package/dist/src/adapters/in-process.adapter.d.ts +140 -0
  4. package/dist/src/adapters/in-process.adapter.d.ts.map +1 -0
  5. package/dist/src/adapters/in-process.adapter.js +86 -0
  6. package/dist/src/adapters/in-process.adapter.js.map +1 -0
  7. package/dist/src/adapters/index.d.ts +18 -0
  8. package/dist/src/adapters/index.d.ts.map +1 -0
  9. package/dist/src/adapters/index.js +35 -0
  10. package/dist/src/adapters/index.js.map +1 -0
  11. package/dist/src/builder/batch-builder.d.ts +26 -0
  12. package/dist/src/builder/batch-builder.d.ts.map +1 -0
  13. package/dist/src/builder/batch-builder.js +25 -0
  14. package/dist/src/builder/batch-builder.js.map +1 -0
  15. package/dist/src/builder/flow-builder.d.ts +59 -0
  16. package/dist/src/builder/flow-builder.d.ts.map +1 -0
  17. package/dist/src/builder/flow-builder.js +115 -0
  18. package/dist/src/builder/flow-builder.js.map +1 -0
  19. package/dist/src/builder/index.d.ts +5 -0
  20. package/dist/src/builder/index.d.ts.map +1 -0
  21. package/dist/src/builder/index.js +23 -0
  22. package/dist/src/builder/index.js.map +1 -0
  23. package/dist/src/builder/job-builder.d.ts +76 -0
  24. package/dist/src/builder/job-builder.d.ts.map +1 -0
  25. package/dist/src/builder/job-builder.js +166 -0
  26. package/dist/src/builder/job-builder.js.map +1 -0
  27. package/dist/src/builder/step-builder.d.ts +74 -0
  28. package/dist/src/builder/step-builder.d.ts.map +1 -0
  29. package/dist/src/builder/step-builder.js +144 -0
  30. package/dist/src/builder/step-builder.js.map +1 -0
  31. package/dist/src/compiler/builder-types.d.ts +20 -0
  32. package/dist/src/compiler/builder-types.d.ts.map +1 -0
  33. package/dist/src/compiler/builder-types.js +6 -0
  34. package/dist/src/compiler/builder-types.js.map +1 -0
  35. package/dist/src/compiler/definition-compiler.d.ts +99 -0
  36. package/dist/src/compiler/definition-compiler.d.ts.map +1 -0
  37. package/dist/src/compiler/definition-compiler.js +257 -0
  38. package/dist/src/compiler/definition-compiler.js.map +1 -0
  39. package/dist/src/compiler/index.d.ts +3 -0
  40. package/dist/src/compiler/index.d.ts.map +1 -0
  41. package/dist/src/compiler/index.js +21 -0
  42. package/dist/src/compiler/index.js.map +1 -0
  43. package/dist/src/core/errors.d.ts +77 -0
  44. package/dist/src/core/errors.d.ts.map +1 -0
  45. package/dist/src/core/errors.js +170 -0
  46. package/dist/src/core/errors.js.map +1 -0
  47. package/dist/src/core/execution-context/index.d.ts +4 -0
  48. package/dist/src/core/execution-context/index.d.ts.map +1 -0
  49. package/dist/src/core/execution-context/index.js +22 -0
  50. package/dist/src/core/execution-context/index.js.map +1 -0
  51. package/dist/src/core/execution-context/json-value.d.ts +5 -0
  52. package/dist/src/core/execution-context/json-value.d.ts.map +1 -0
  53. package/dist/src/core/execution-context/json-value.js +6 -0
  54. package/dist/src/core/execution-context/json-value.js.map +1 -0
  55. package/dist/src/core/execution-context/serializer.d.ts +4 -0
  56. package/dist/src/core/execution-context/serializer.d.ts.map +1 -0
  57. package/dist/src/core/execution-context/serializer.js +34 -0
  58. package/dist/src/core/execution-context/serializer.js.map +1 -0
  59. package/dist/src/core/execution-context/validator.d.ts +18 -0
  60. package/dist/src/core/execution-context/validator.d.ts.map +1 -0
  61. package/dist/src/core/execution-context/validator.js +90 -0
  62. package/dist/src/core/execution-context/validator.js.map +1 -0
  63. package/dist/src/core/index.d.ts +8 -0
  64. package/dist/src/core/index.d.ts.map +1 -0
  65. package/dist/src/core/index.js +26 -0
  66. package/dist/src/core/index.js.map +1 -0
  67. package/dist/src/core/ir/decider-definition.d.ts +20 -0
  68. package/dist/src/core/ir/decider-definition.d.ts.map +1 -0
  69. package/dist/src/core/ir/decider-definition.js +6 -0
  70. package/dist/src/core/ir/decider-definition.js.map +1 -0
  71. package/dist/src/core/ir/index.d.ts +8 -0
  72. package/dist/src/core/ir/index.d.ts.map +1 -0
  73. package/dist/src/core/ir/index.js +26 -0
  74. package/dist/src/core/ir/index.js.map +1 -0
  75. package/dist/src/core/ir/job-definition.d.ts +15 -0
  76. package/dist/src/core/ir/job-definition.d.ts.map +1 -0
  77. package/dist/src/core/ir/job-definition.js +6 -0
  78. package/dist/src/core/ir/job-definition.js.map +1 -0
  79. package/dist/src/core/ir/listener-definition.d.ts +10 -0
  80. package/dist/src/core/ir/listener-definition.d.ts.map +1 -0
  81. package/dist/src/core/ir/listener-definition.js +6 -0
  82. package/dist/src/core/ir/listener-definition.js.map +1 -0
  83. package/dist/src/core/ir/policy-config.d.ts +24 -0
  84. package/dist/src/core/ir/policy-config.d.ts.map +1 -0
  85. package/dist/src/core/ir/policy-config.js +6 -0
  86. package/dist/src/core/ir/policy-config.js.map +1 -0
  87. package/dist/src/core/ir/refs.d.ts +42 -0
  88. package/dist/src/core/ir/refs.d.ts.map +1 -0
  89. package/dist/src/core/ir/refs.js +18 -0
  90. package/dist/src/core/ir/refs.js.map +1 -0
  91. package/dist/src/core/ir/step-definition.d.ts +59 -0
  92. package/dist/src/core/ir/step-definition.d.ts.map +1 -0
  93. package/dist/src/core/ir/step-definition.js +6 -0
  94. package/dist/src/core/ir/step-definition.js.map +1 -0
  95. package/dist/src/core/ir/transition-definition.d.ts +8 -0
  96. package/dist/src/core/ir/transition-definition.d.ts.map +1 -0
  97. package/dist/src/core/ir/transition-definition.js +6 -0
  98. package/dist/src/core/ir/transition-definition.js.map +1 -0
  99. package/dist/src/core/item/index.d.ts +2 -0
  100. package/dist/src/core/item/index.d.ts.map +1 -0
  101. package/dist/src/core/item/index.js +20 -0
  102. package/dist/src/core/item/index.js.map +1 -0
  103. package/dist/src/core/item/interfaces.d.ts +64 -0
  104. package/dist/src/core/item/interfaces.d.ts.map +1 -0
  105. package/dist/src/core/item/interfaces.js +6 -0
  106. package/dist/src/core/item/interfaces.js.map +1 -0
  107. package/dist/src/core/repository/index.d.ts +3 -0
  108. package/dist/src/core/repository/index.d.ts.map +1 -0
  109. package/dist/src/core/repository/index.js +21 -0
  110. package/dist/src/core/repository/index.js.map +1 -0
  111. package/dist/src/core/repository/job-repository.d.ts +60 -0
  112. package/dist/src/core/repository/job-repository.d.ts.map +1 -0
  113. package/dist/src/core/repository/job-repository.js +27 -0
  114. package/dist/src/core/repository/job-repository.js.map +1 -0
  115. package/dist/src/core/repository/types.d.ts +84 -0
  116. package/dist/src/core/repository/types.d.ts.map +1 -0
  117. package/dist/src/core/repository/types.js +6 -0
  118. package/dist/src/core/repository/types.js.map +1 -0
  119. package/dist/src/core/status.d.ts +29 -0
  120. package/dist/src/core/status.d.ts.map +1 -0
  121. package/dist/src/core/status.js +58 -0
  122. package/dist/src/core/status.js.map +1 -0
  123. package/dist/src/core/transaction/index.d.ts +2 -0
  124. package/dist/src/core/transaction/index.d.ts.map +1 -0
  125. package/dist/src/core/transaction/index.js +20 -0
  126. package/dist/src/core/transaction/index.js.map +1 -0
  127. package/dist/src/core/transaction/transaction-manager.d.ts +8 -0
  128. package/dist/src/core/transaction/transaction-manager.d.ts.map +1 -0
  129. package/dist/src/core/transaction/transaction-manager.js +14 -0
  130. package/dist/src/core/transaction/transaction-manager.js.map +1 -0
  131. package/dist/src/core/validation/definition-validator.d.ts +46 -0
  132. package/dist/src/core/validation/definition-validator.d.ts.map +1 -0
  133. package/dist/src/core/validation/definition-validator.js +177 -0
  134. package/dist/src/core/validation/definition-validator.js.map +1 -0
  135. package/dist/src/core/validation/index.d.ts +2 -0
  136. package/dist/src/core/validation/index.d.ts.map +1 -0
  137. package/dist/src/core/validation/index.js +20 -0
  138. package/dist/src/core/validation/index.js.map +1 -0
  139. package/dist/src/decorators/constants.d.ts +10 -0
  140. package/dist/src/decorators/constants.d.ts.map +1 -0
  141. package/dist/src/decorators/constants.js +50 -0
  142. package/dist/src/decorators/constants.js.map +1 -0
  143. package/dist/src/decorators/flow.decorator.d.ts +25 -0
  144. package/dist/src/decorators/flow.decorator.d.ts.map +1 -0
  145. package/dist/src/decorators/flow.decorator.js +19 -0
  146. package/dist/src/decorators/flow.decorator.js.map +1 -0
  147. package/dist/src/decorators/index.d.ts +8 -0
  148. package/dist/src/decorators/index.d.ts.map +1 -0
  149. package/dist/src/decorators/index.js +26 -0
  150. package/dist/src/decorators/index.js.map +1 -0
  151. package/dist/src/decorators/item.decorators.d.ts +32 -0
  152. package/dist/src/decorators/item.decorators.d.ts.map +1 -0
  153. package/dist/src/decorators/item.decorators.js +40 -0
  154. package/dist/src/decorators/item.decorators.js.map +1 -0
  155. package/dist/src/decorators/job.decorator.d.ts +11 -0
  156. package/dist/src/decorators/job.decorator.d.ts.map +1 -0
  157. package/dist/src/decorators/job.decorator.js +17 -0
  158. package/dist/src/decorators/job.decorator.js.map +1 -0
  159. package/dist/src/decorators/listener.decorators.d.ts +56 -0
  160. package/dist/src/decorators/listener.decorators.d.ts.map +1 -0
  161. package/dist/src/decorators/listener.decorators.js +157 -0
  162. package/dist/src/decorators/listener.decorators.js.map +1 -0
  163. package/dist/src/decorators/step.decorator.d.ts +25 -0
  164. package/dist/src/decorators/step.decorator.d.ts.map +1 -0
  165. package/dist/src/decorators/step.decorator.js +21 -0
  166. package/dist/src/decorators/step.decorator.js.map +1 -0
  167. package/dist/src/decorators/tasklet.decorator.d.ts +7 -0
  168. package/dist/src/decorators/tasklet.decorator.d.ts.map +1 -0
  169. package/dist/src/decorators/tasklet.decorator.js +21 -0
  170. package/dist/src/decorators/tasklet.decorator.js.map +1 -0
  171. package/dist/src/execution/batch-worker-runner.d.ts +27 -0
  172. package/dist/src/execution/batch-worker-runner.d.ts.map +1 -0
  173. package/dist/src/execution/batch-worker-runner.js +147 -0
  174. package/dist/src/execution/batch-worker-runner.js.map +1 -0
  175. package/dist/src/execution/chunk-step-executor.d.ts +86 -0
  176. package/dist/src/execution/chunk-step-executor.d.ts.map +1 -0
  177. package/dist/src/execution/chunk-step-executor.js +482 -0
  178. package/dist/src/execution/chunk-step-executor.js.map +1 -0
  179. package/dist/src/execution/execution-strategy.d.ts +110 -0
  180. package/dist/src/execution/execution-strategy.d.ts.map +1 -0
  181. package/dist/src/execution/execution-strategy.js +13 -0
  182. package/dist/src/execution/execution-strategy.js.map +1 -0
  183. package/dist/src/execution/external-task-execution-strategy.d.ts +36 -0
  184. package/dist/src/execution/external-task-execution-strategy.d.ts.map +1 -0
  185. package/dist/src/execution/external-task-execution-strategy.js +97 -0
  186. package/dist/src/execution/external-task-execution-strategy.js.map +1 -0
  187. package/dist/src/execution/in-process-execution-strategy.d.ts +129 -0
  188. package/dist/src/execution/in-process-execution-strategy.d.ts.map +1 -0
  189. package/dist/src/execution/in-process-execution-strategy.js +141 -0
  190. package/dist/src/execution/in-process-execution-strategy.js.map +1 -0
  191. package/dist/src/execution/index.d.ts +14 -0
  192. package/dist/src/execution/index.d.ts.map +1 -0
  193. package/dist/src/execution/index.js +32 -0
  194. package/dist/src/execution/index.js.map +1 -0
  195. package/dist/src/execution/job-executor.d.ts +145 -0
  196. package/dist/src/execution/job-executor.d.ts.map +1 -0
  197. package/dist/src/execution/job-executor.js +475 -0
  198. package/dist/src/execution/job-executor.js.map +1 -0
  199. package/dist/src/execution/job-explorer.d.ts +15 -0
  200. package/dist/src/execution/job-explorer.d.ts.map +1 -0
  201. package/dist/src/execution/job-explorer.js +84 -0
  202. package/dist/src/execution/job-explorer.js.map +1 -0
  203. package/dist/src/execution/job-key.d.ts +3 -0
  204. package/dist/src/execution/job-key.d.ts.map +1 -0
  205. package/dist/src/execution/job-key.js +43 -0
  206. package/dist/src/execution/job-key.js.map +1 -0
  207. package/dist/src/execution/job-launcher.d.ts +75 -0
  208. package/dist/src/execution/job-launcher.d.ts.map +1 -0
  209. package/dist/src/execution/job-launcher.js +112 -0
  210. package/dist/src/execution/job-launcher.js.map +1 -0
  211. package/dist/src/execution/job-operator.d.ts +22 -0
  212. package/dist/src/execution/job-operator.d.ts.map +1 -0
  213. package/dist/src/execution/job-operator.js +125 -0
  214. package/dist/src/execution/job-operator.js.map +1 -0
  215. package/dist/src/execution/listener-invoker.d.ts +164 -0
  216. package/dist/src/execution/listener-invoker.d.ts.map +1 -0
  217. package/dist/src/execution/listener-invoker.js +246 -0
  218. package/dist/src/execution/listener-invoker.js.map +1 -0
  219. package/dist/src/execution/ref-resolver.d.ts +40 -0
  220. package/dist/src/execution/ref-resolver.d.ts.map +1 -0
  221. package/dist/src/execution/ref-resolver.js +41 -0
  222. package/dist/src/execution/ref-resolver.js.map +1 -0
  223. package/dist/src/execution/tasklet-step-executor.d.ts +79 -0
  224. package/dist/src/execution/tasklet-step-executor.d.ts.map +1 -0
  225. package/dist/src/execution/tasklet-step-executor.js +138 -0
  226. package/dist/src/execution/tasklet-step-executor.js.map +1 -0
  227. package/dist/src/explorer/batch-explorer.d.ts +138 -0
  228. package/dist/src/explorer/batch-explorer.d.ts.map +1 -0
  229. package/dist/src/explorer/batch-explorer.js +167 -0
  230. package/dist/src/explorer/batch-explorer.js.map +1 -0
  231. package/dist/src/explorer/index.d.ts +2 -0
  232. package/dist/src/explorer/index.d.ts.map +1 -0
  233. package/dist/src/explorer/index.js +20 -0
  234. package/dist/src/explorer/index.js.map +1 -0
  235. package/dist/src/flow/flow-evaluator.d.ts +30 -0
  236. package/dist/src/flow/flow-evaluator.d.ts.map +1 -0
  237. package/dist/src/flow/flow-evaluator.js +80 -0
  238. package/dist/src/flow/flow-evaluator.js.map +1 -0
  239. package/dist/src/flow/index.d.ts +2 -0
  240. package/dist/src/flow/index.d.ts.map +1 -0
  241. package/dist/src/flow/index.js +20 -0
  242. package/dist/src/flow/index.js.map +1 -0
  243. package/dist/src/index.d.ts +18 -0
  244. package/dist/src/index.d.ts.map +1 -0
  245. package/dist/src/index.js +90 -0
  246. package/dist/src/index.js.map +1 -0
  247. package/dist/src/io/checkpoint.d.ts +7 -0
  248. package/dist/src/io/checkpoint.d.ts.map +1 -0
  249. package/dist/src/io/checkpoint.js +56 -0
  250. package/dist/src/io/checkpoint.js.map +1 -0
  251. package/dist/src/io/database.d.ts +50 -0
  252. package/dist/src/io/database.d.ts.map +1 -0
  253. package/dist/src/io/database.js +108 -0
  254. package/dist/src/io/database.js.map +1 -0
  255. package/dist/src/io/file-readers.d.ts +54 -0
  256. package/dist/src/io/file-readers.d.ts.map +1 -0
  257. package/dist/src/io/file-readers.js +167 -0
  258. package/dist/src/io/file-readers.js.map +1 -0
  259. package/dist/src/io/file-writers.d.ts +31 -0
  260. package/dist/src/io/file-writers.d.ts.map +1 -0
  261. package/dist/src/io/file-writers.js +80 -0
  262. package/dist/src/io/file-writers.js.map +1 -0
  263. package/dist/src/io/index.d.ts +6 -0
  264. package/dist/src/io/index.d.ts.map +1 -0
  265. package/dist/src/io/index.js +24 -0
  266. package/dist/src/io/index.js.map +1 -0
  267. package/dist/src/io/s3.d.ts +50 -0
  268. package/dist/src/io/s3.d.ts.map +1 -0
  269. package/dist/src/io/s3.js +96 -0
  270. package/dist/src/io/s3.js.map +1 -0
  271. package/dist/src/listeners/builtin-listeners.d.ts +77 -0
  272. package/dist/src/listeners/builtin-listeners.d.ts.map +1 -0
  273. package/dist/src/listeners/builtin-listeners.js +108 -0
  274. package/dist/src/listeners/builtin-listeners.js.map +1 -0
  275. package/dist/src/listeners/index.d.ts +8 -0
  276. package/dist/src/listeners/index.d.ts.map +1 -0
  277. package/dist/src/listeners/index.js +25 -0
  278. package/dist/src/listeners/index.js.map +1 -0
  279. package/dist/src/module/adapter-options.d.ts +39 -0
  280. package/dist/src/module/adapter-options.d.ts.map +1 -0
  281. package/dist/src/module/adapter-options.js +34 -0
  282. package/dist/src/module/adapter-options.js.map +1 -0
  283. package/dist/src/module/adapter.d.ts +157 -0
  284. package/dist/src/module/adapter.d.ts.map +1 -0
  285. package/dist/src/module/adapter.js +80 -0
  286. package/dist/src/module/adapter.js.map +1 -0
  287. package/dist/src/module/batch-schedule-registry.d.ts +110 -0
  288. package/dist/src/module/batch-schedule-registry.d.ts.map +1 -0
  289. package/dist/src/module/batch-schedule-registry.js +0 -0
  290. package/dist/src/module/batch-schedule-registry.js.map +1 -0
  291. package/dist/src/module/index.d.ts +14 -0
  292. package/dist/src/module/index.d.ts.map +1 -0
  293. package/dist/src/module/index.js +31 -0
  294. package/dist/src/module/index.js.map +1 -0
  295. package/dist/src/module/nest-batch.module.d.ts +236 -0
  296. package/dist/src/module/nest-batch.module.d.ts.map +1 -0
  297. package/dist/src/module/nest-batch.module.js +475 -0
  298. package/dist/src/module/nest-batch.module.js.map +1 -0
  299. package/dist/src/module/tokens.d.ts +83 -0
  300. package/dist/src/module/tokens.d.ts.map +1 -0
  301. package/dist/src/module/tokens.js +58 -0
  302. package/dist/src/module/tokens.js.map +1 -0
  303. package/dist/src/observability/event-types.d.ts +55 -0
  304. package/dist/src/observability/event-types.d.ts.map +1 -0
  305. package/dist/src/observability/event-types.js +36 -0
  306. package/dist/src/observability/event-types.js.map +1 -0
  307. package/dist/src/observability/exporters.d.ts +35 -0
  308. package/dist/src/observability/exporters.d.ts.map +1 -0
  309. package/dist/src/observability/exporters.js +93 -0
  310. package/dist/src/observability/exporters.js.map +1 -0
  311. package/dist/src/observability/index.d.ts +3 -0
  312. package/dist/src/observability/index.d.ts.map +1 -0
  313. package/dist/src/observability/index.js +21 -0
  314. package/dist/src/observability/index.js.map +1 -0
  315. package/dist/src/partition-helpers.d.ts +127 -0
  316. package/dist/src/partition-helpers.d.ts.map +1 -0
  317. package/dist/src/partition-helpers.js +136 -0
  318. package/dist/src/partition-helpers.js.map +1 -0
  319. package/dist/src/policies/backoff.d.ts +3 -0
  320. package/dist/src/policies/backoff.d.ts.map +1 -0
  321. package/dist/src/policies/backoff.js +34 -0
  322. package/dist/src/policies/backoff.js.map +1 -0
  323. package/dist/src/policies/index.d.ts +4 -0
  324. package/dist/src/policies/index.d.ts.map +1 -0
  325. package/dist/src/policies/index.js +22 -0
  326. package/dist/src/policies/index.js.map +1 -0
  327. package/dist/src/policies/retry-policy.d.ts +13 -0
  328. package/dist/src/policies/retry-policy.d.ts.map +1 -0
  329. package/dist/src/policies/retry-policy.js +55 -0
  330. package/dist/src/policies/retry-policy.js.map +1 -0
  331. package/dist/src/policies/skip-policy.d.ts +12 -0
  332. package/dist/src/policies/skip-policy.d.ts.map +1 -0
  333. package/dist/src/policies/skip-policy.js +44 -0
  334. package/dist/src/policies/skip-policy.js.map +1 -0
  335. package/dist/src/registry/index.d.ts +2 -0
  336. package/dist/src/registry/index.d.ts.map +1 -0
  337. package/dist/src/registry/index.js +20 -0
  338. package/dist/src/registry/index.js.map +1 -0
  339. package/dist/src/registry/job-registry.d.ts +16 -0
  340. package/dist/src/registry/job-registry.d.ts.map +1 -0
  341. package/dist/src/registry/job-registry.js +50 -0
  342. package/dist/src/registry/job-registry.js.map +1 -0
  343. package/dist/src/repository/id-generator.d.ts +18 -0
  344. package/dist/src/repository/id-generator.d.ts.map +1 -0
  345. package/dist/src/repository/id-generator.js +37 -0
  346. package/dist/src/repository/id-generator.js.map +1 -0
  347. package/dist/src/repository/in-memory/in-memory-job-repository.d.ts +49 -0
  348. package/dist/src/repository/in-memory/in-memory-job-repository.d.ts.map +1 -0
  349. package/dist/src/repository/in-memory/in-memory-job-repository.js +291 -0
  350. package/dist/src/repository/in-memory/in-memory-job-repository.js.map +1 -0
  351. package/dist/src/repository/in-memory/index.d.ts +2 -0
  352. package/dist/src/repository/in-memory/index.d.ts.map +1 -0
  353. package/dist/src/repository/in-memory/index.js +20 -0
  354. package/dist/src/repository/in-memory/index.js.map +1 -0
  355. package/dist/src/repository/index.d.ts +4 -0
  356. package/dist/src/repository/index.d.ts.map +1 -0
  357. package/dist/src/repository/index.js +22 -0
  358. package/dist/src/repository/index.js.map +1 -0
  359. package/dist/src/repository/uuid-v7.d.ts +20 -0
  360. package/dist/src/repository/uuid-v7.d.ts.map +1 -0
  361. package/dist/src/repository/uuid-v7.js +31 -0
  362. package/dist/src/repository/uuid-v7.js.map +1 -0
  363. package/dist/src/scheduling/batch-scheduled.d.ts +87 -0
  364. package/dist/src/scheduling/batch-scheduled.d.ts.map +1 -0
  365. package/dist/src/scheduling/batch-scheduled.js +170 -0
  366. package/dist/src/scheduling/batch-scheduled.js.map +1 -0
  367. package/dist/src/transaction/in-memory-transaction-manager.d.ts +16 -0
  368. package/dist/src/transaction/in-memory-transaction-manager.d.ts.map +1 -0
  369. package/dist/src/transaction/in-memory-transaction-manager.js +33 -0
  370. package/dist/src/transaction/in-memory-transaction-manager.js.map +1 -0
  371. package/dist/src/transaction/index.d.ts +2 -0
  372. package/dist/src/transaction/index.d.ts.map +1 -0
  373. package/dist/src/transaction/index.js +20 -0
  374. package/dist/src/transaction/index.js.map +1 -0
  375. package/dist/tests/contracts/index.d.ts +26 -0
  376. package/dist/tests/contracts/index.d.ts.map +1 -0
  377. package/dist/tests/contracts/index.js +37 -0
  378. package/dist/tests/contracts/index.js.map +1 -0
  379. package/dist/tests/contracts/job-repository.contract.d.ts +46 -0
  380. package/dist/tests/contracts/job-repository.contract.d.ts.map +1 -0
  381. package/dist/tests/contracts/job-repository.contract.js +644 -0
  382. package/dist/tests/contracts/job-repository.contract.js.map +1 -0
  383. package/package.json +80 -0
  384. package/src/adapters/in-process.adapter.ts +182 -0
  385. package/src/adapters/index.ts +17 -0
  386. package/src/builder/batch-builder.ts +32 -0
  387. package/src/builder/flow-builder.ts +141 -0
  388. package/src/builder/index.ts +4 -0
  389. package/src/builder/job-builder.ts +206 -0
  390. package/src/builder/step-builder.ts +190 -0
  391. package/src/compiler/builder-types.ts +27 -0
  392. package/src/compiler/definition-compiler.ts +325 -0
  393. package/src/compiler/index.ts +2 -0
  394. package/src/core/errors.ts +125 -0
  395. package/src/core/execution-context/index.ts +3 -0
  396. package/src/core/execution-context/json-value.ts +3 -0
  397. package/src/core/execution-context/serializer.ts +21 -0
  398. package/src/core/execution-context/validator.ts +103 -0
  399. package/src/core/index.ts +7 -0
  400. package/src/core/ir/decider-definition.ts +25 -0
  401. package/src/core/ir/index.ts +7 -0
  402. package/src/core/ir/job-definition.ts +15 -0
  403. package/src/core/ir/listener-definition.ts +19 -0
  404. package/src/core/ir/policy-config.ts +19 -0
  405. package/src/core/ir/refs.ts +42 -0
  406. package/src/core/ir/step-definition.ts +62 -0
  407. package/src/core/ir/transition-definition.ts +9 -0
  408. package/src/core/item/index.ts +1 -0
  409. package/src/core/item/interfaces.ts +70 -0
  410. package/src/core/repository/index.ts +2 -0
  411. package/src/core/repository/job-repository.ts +100 -0
  412. package/src/core/repository/types.ts +91 -0
  413. package/src/core/status.ts +31 -0
  414. package/src/core/transaction/index.ts +1 -0
  415. package/src/core/transaction/transaction-manager.ts +8 -0
  416. package/src/core/validation/definition-validator.ts +215 -0
  417. package/src/core/validation/index.ts +1 -0
  418. package/src/decorators/constants.ts +9 -0
  419. package/src/decorators/flow.decorator.ts +31 -0
  420. package/src/decorators/index.ts +7 -0
  421. package/src/decorators/item.decorators.ts +51 -0
  422. package/src/decorators/job.decorator.ts +16 -0
  423. package/src/decorators/listener.decorators.ts +142 -0
  424. package/src/decorators/step.decorator.ts +33 -0
  425. package/src/decorators/tasklet.decorator.ts +14 -0
  426. package/src/execution/batch-worker-runner.ts +142 -0
  427. package/src/execution/chunk-step-executor.ts +594 -0
  428. package/src/execution/execution-strategy.ts +115 -0
  429. package/src/execution/external-task-execution-strategy.ts +104 -0
  430. package/src/execution/in-process-execution-strategy.ts +207 -0
  431. package/src/execution/index.ts +13 -0
  432. package/src/execution/job-executor.ts +553 -0
  433. package/src/execution/job-explorer.ts +73 -0
  434. package/src/execution/job-key.ts +35 -0
  435. package/src/execution/job-launcher.ts +132 -0
  436. package/src/execution/job-operator.ts +127 -0
  437. package/src/execution/listener-invoker.ts +389 -0
  438. package/src/execution/ref-resolver.ts +64 -0
  439. package/src/execution/tasklet-step-executor.ts +182 -0
  440. package/src/explorer/batch-explorer.ts +251 -0
  441. package/src/explorer/index.ts +1 -0
  442. package/src/flow/flow-evaluator.ts +89 -0
  443. package/src/flow/index.ts +1 -0
  444. package/src/index.ts +24 -0
  445. package/src/io/checkpoint.ts +47 -0
  446. package/src/io/database.ts +114 -0
  447. package/src/io/file-readers.ts +191 -0
  448. package/src/io/file-writers.ts +99 -0
  449. package/src/io/index.ts +5 -0
  450. package/src/io/s3.ts +117 -0
  451. package/src/listeners/builtin-listeners.ts +151 -0
  452. package/src/listeners/index.ts +7 -0
  453. package/src/module/adapter-options.ts +38 -0
  454. package/src/module/adapter.ts +160 -0
  455. package/src/module/batch-schedule-registry.ts +0 -0
  456. package/src/module/index.ts +13 -0
  457. package/src/module/nest-batch.module.ts +674 -0
  458. package/src/module/tokens.ts +95 -0
  459. package/src/observability/event-types.ts +61 -0
  460. package/src/observability/exporters.ts +96 -0
  461. package/src/observability/index.ts +2 -0
  462. package/src/partition-helpers.ts +204 -0
  463. package/src/policies/backoff.ts +22 -0
  464. package/src/policies/index.ts +3 -0
  465. package/src/policies/retry-policy.ts +57 -0
  466. package/src/policies/skip-policy.ts +51 -0
  467. package/src/registry/index.ts +1 -0
  468. package/src/registry/job-registry.ts +42 -0
  469. package/src/repository/id-generator.ts +25 -0
  470. package/src/repository/in-memory/in-memory-job-repository.ts +334 -0
  471. package/src/repository/in-memory/index.ts +1 -0
  472. package/src/repository/index.ts +3 -0
  473. package/src/repository/uuid-v7.ts +40 -0
  474. package/src/scheduling/batch-scheduled.ts +257 -0
  475. package/src/transaction/in-memory-transaction-manager.ts +23 -0
  476. package/src/transaction/index.ts +1 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/execution/job-executor.ts"],"sourcesContent":["import { Injectable, Inject, Optional, forwardRef, Logger } from '@nestjs/common';\nimport type { JobDefinition, ListenerDefinition } from '../core/ir';\nimport { RefKind, type ListenerRef } from '../core/ir';\nimport { JobRepository, type JobParameters, type JobExecution } from '../core/repository';\nimport { TransactionManager } from '../core/transaction';\nimport { StepStatus, JobStatus, FlowExecutionStatus } from '../core/status';\nimport { JobNotRestartableError } from '../core/errors';\nimport { TaskletStepExecutor, type StepExecutionResult } from './tasklet-step-executor';\nimport { ChunkStepExecutor, type ChunkExecutionResult } from './chunk-step-executor';\nimport {\n ListenerInvoker,\n type ResolverMap,\n type ListenerResolver,\n} from './listener-invoker';\nimport { FlowEvaluator } from '../flow/flow-evaluator';\nimport {\n BATCH_EVENT,\n NoopBatchObserver,\n type BatchEvent,\n type BatchObserver,\n} from '../observability';\n\n/**\n * Result type that covers both tasklet and chunk step outcomes.\n * Structurally compatible with `StepExecutionPatch` so the executor\n * can forward it directly to `updateStepExecution`.\n *\n * The only field chunk has but tasklet doesn't is `commitCount`; for\n * tasklet results it stays `undefined` and `updateStepExecution`\n * happily ignores undefined fields (merge semantics, see repository).\n */\ntype StepResult = StepExecutionResult | ChunkExecutionResult;\n\n/**\n * JobExecutor — drives a single JobExecution to completion.\n *\n * Flow (per ORACLE verdict 3c):\n * 1. Mark execution as STARTED.\n * 2. `before:job:*` listeners.\n * 3. Loop:\n * a. Look up the current step (jobDef.steps[currentStepId]). If the\n * step is missing, mark the job FAILED with exit code\n * `NO_SUCH_STEP` and break.\n * b. Create a StepExecution, run it (tasklet or chunk), and persist\n * the result via `updateStepExecution`. During the run, the\n * step's own `after-step:*` listeners fire (see\n * `TaskletStepExecutor.execute` step 4 / `ChunkStepExecutor`).\n * Those listeners run BEFORE we evaluate transitions so they get\n * a chance to mutate the result (e.g. flip COMPLETED → FAILED)\n * and the resulting flow routing sees the override.\n * c. Map the (possibly overridden) step status to a\n * `FlowExecutionStatus` and ask the `FlowEvaluator` for the next\n * step. `null` means END.\n * d. If the step FAILED and the evaluator returned `null`\n * (no recovery transition matches), short-circuit the job to\n * FAILED — we must not continue running subsequent steps\n * declared in the graph, because none are reachable.\n * 4. `after:job:*` listeners (with the final status).\n *\n * Out of scope (future tasks):\n * - Concurrency control (Task 38).\n * - `on-error:job:*` listener invocation when the executor itself\n * throws (the catch block can be wired to it in a follow-up).\n */\n@Injectable()\nexport class JobExecutor {\n private readonly logger = new Logger(JobExecutor.name);\n\n constructor(\n private readonly repository: JobRepository,\n @Inject(forwardRef(() => TransactionManager))\n private readonly transactionManager: TransactionManager,\n private readonly taskletExecutor: TaskletStepExecutor,\n private readonly chunkExecutor: ChunkStepExecutor,\n private readonly listenerInvoker: ListenerInvoker,\n private readonly flowEvaluator: FlowEvaluator,\n @Optional()\n private readonly observer: BatchObserver = new NoopBatchObserver(),\n ) {}\n\n /**\n * Execute a JobExecution against its `JobDefinition`. Returns the\n * final, persisted `JobExecution` (status = COMPLETED | FAILED).\n *\n * Restart behavior (per Metis verdict 3b — restartable opt-in, per\n * ORACLE 3b — default-on for persisted repositories):\n * - If `execution.status` is `FAILED` on entry, this is a restart\n * attempt. We require `jobDef.restartable === true`; otherwise we\n * throw `JobNotRestartableError` and leave the execution alone.\n * - For each chunk step, we look up the latest FAILED StepExecution\n * for that step in this job execution. If one exists, we read its\n * ExecutionContext's `lastChunkIndex` checkpoint and pass it to the\n * `ChunkStepExecutor` as `resumeFromChunkIndex`, which then skips\n * chunks ≤ that index. Tasklet steps always re-run from scratch\n * (they have no chunk-level resume granularity in this MVP).\n *\n * Partition routing (T8): the optional third argument carries the\n * `partitionIndex` / `partitionCount` pair the transport attached\n * to the job. When set, the chunk executor bounds the read loop\n * to the partition's range (see `packages/core/src/partition-helpers.ts`).\n */\n async execute(\n execution: JobExecution,\n jobDef: JobDefinition,\n partition?: { partitionIndex?: number; partitionCount?: number },\n ): Promise<JobExecution> {\n // Capture the pre-execute status. For a fresh launch, the launcher\n // created the execution with status STARTING; for a restart, the\n // caller (JobLauncher.run) hands us a terminal execution that can\n // be resumed.\n const isRestart =\n execution.status === JobStatus.FAILED || execution.status === JobStatus.STOPPED;\n if (isRestart && !jobDef.restartable) {\n throw new JobNotRestartableError(jobDef.id);\n }\n\n await this.repository.updateJobExecution(execution.id, {\n status: JobStatus.STARTED,\n startTime: new Date(),\n });\n\n await this.emit({\n type: BATCH_EVENT.JOB_STARTED,\n timestamp: new Date(),\n jobExecutionId: execution.id,\n data: { jobName: jobDef.id },\n });\n\n // Build the full resolver map once. The same map powers both the\n // job-level `invokeBefore` / `invokeAfter` calls below and the\n // step-level resolvers handed to the TaskletStepExecutor (derived\n // by `buildLegacyStepResolvers` into the legacy key shape). Building\n // it once per execution avoids re-walking the IR on every step.\n const jobResolvers = this.buildResolverMap(jobDef);\n const stepResolvers = this.buildLegacyStepResolvers(jobResolvers);\n\n await this.listenerInvoker.invokeBefore(jobResolvers, 'job', {\n jobExecutionId: execution.id,\n stepExecutionId: '<job>',\n });\n\n // Cache the step order once. `Object.keys` returns insertion order\n // for string keys (per ES2015+), so this is the canonical\n // declaration order — used for the linear fallback below.\n const stepOrder = Object.keys(jobDef.steps);\n\n let currentStepId: string | null = jobDef.startStepId;\n let finalStatus: JobStatus = JobStatus.COMPLETED;\n let currentStepExecutionId: string | null = null;\n\n try {\n while (currentStepId !== null) {\n const step = jobDef.steps[currentStepId];\n if (!step) {\n await this.repository.updateJobExecution(execution.id, {\n status: JobStatus.FAILED,\n endTime: new Date(),\n exitCode: 'NO_SUCH_STEP',\n exitMessage: `Step \"${currentStepId}\" not found`,\n });\n finalStatus = JobStatus.FAILED;\n break;\n }\n\n // Restart path: if this is a restart and the current step is a\n // chunk step, locate the latest FAILED step execution for the\n // same step name and load its `lastChunkIndex` checkpoint. That\n // value is passed to the chunk executor as `resumeFromChunkIndex`.\n // For tasklet steps (and chunk steps with no prior failure) we\n // leave `resumeFromChunkIndex` undefined — the chunk executor\n // treats undefined as \"start from the beginning\".\n //\n // Look this up BEFORE createStepExecution so the just-created\n // STARTING step isn't returned as the \"latest\" entry.\n let resumeFromChunkIndex: number | undefined;\n if (isRestart && step.kind === 'chunk') {\n const priorFailed = await this.repository.findLatestStepExecution(execution.id, step.id);\n if (priorFailed && priorFailed.status === StepStatus.FAILED) {\n resumeFromChunkIndex = await this.getLastCheckpoint(priorFailed.id);\n }\n }\n\n const stepExecution = await this.repository.createStepExecution(execution.id, step.id);\n currentStepExecutionId = stepExecution.id;\n\n await this.emit({\n type: BATCH_EVENT.STEP_STARTED,\n timestamp: new Date(),\n jobExecutionId: execution.id,\n stepExecutionId: stepExecution.id,\n data: { stepId: step.id, kind: step.kind },\n });\n\n let result: StepResult;\n try {\n if (step.kind === 'tasklet') {\n result = await this.taskletExecutor.execute(step, {\n jobExecutionId: execution.id,\n jobRepository: this.repository,\n transactionManager: this.transactionManager,\n listenerInvoker: this.listenerInvoker,\n listenerResolvers: stepResolvers,\n });\n } else {\n // Forward the partition routing (T8) when the transport\n // supplied one. The chunk executor uses the partition\n // index + count + the step's `partitions.range` to bound\n // its read loop. Absent partition args fall through to\n // the 0.1.0 non-partitioned chunk pipeline.\n const partitionArgs =\n partition?.partitionIndex !== undefined && partition?.partitionCount !== undefined\n ? {\n partitionIndex: partition.partitionIndex,\n partitionCount: partition.partitionCount,\n }\n : {};\n result = await this.chunkExecutor.execute(step, {\n jobExecutionId: execution.id,\n stepExecutionId: stepExecution.id,\n jobRepository: this.repository,\n transactionManager: this.transactionManager,\n listenerInvoker: this.listenerInvoker,\n jobExecutionId2: execution.id,\n resolvers: new Map(),\n ...(resumeFromChunkIndex !== undefined ? { resumeFromChunkIndex } : {}),\n ...partitionArgs,\n });\n }\n } catch (stepErr) {\n // The executor itself threw (e.g. resolveReader threw in a\n // chunk step before the executor's own try-catch could catch\n // it). Persist the step as FAILED with the error message and\n // re-raise so the outer handler marks the job FAILED.\n await this.repository.updateStepExecution(stepExecution.id, {\n status: StepStatus.FAILED,\n exitCode: 'FAILED',\n exitMessage: stepErr instanceof Error ? stepErr.message : String(stepErr),\n endTime: new Date(),\n });\n currentStepExecutionId = null;\n throw stepErr;\n }\n currentStepExecutionId = null;\n\n await this.repository.updateStepExecution(stepExecution.id, {\n status: result.status,\n ...(result.readCount !== undefined ? { readCount: result.readCount } : {}),\n ...(result.writeCount !== undefined ? { writeCount: result.writeCount } : {}),\n ...(result.skipCount !== undefined ? { skipCount: result.skipCount } : {}),\n ...('commitCount' in result && result.commitCount !== undefined\n ? { commitCount: result.commitCount }\n : {}),\n exitCode: result.exitCode,\n exitMessage: result.exitMessage,\n endTime: new Date(),\n });\n\n await this.emit({\n type:\n result.status === StepStatus.COMPLETED\n ? BATCH_EVENT.STEP_COMPLETED\n : result.status === StepStatus.FAILED\n ? BATCH_EVENT.STEP_FAILED\n : BATCH_EVENT.STEP_COMPLETED,\n timestamp: new Date(),\n jobExecutionId: execution.id,\n stepExecutionId: stepExecution.id,\n data: {\n stepId: step.id,\n status: result.status,\n ...(result.exitCode !== undefined ? { exitCode: result.exitCode } : {}),\n },\n });\n\n // Map StepStatus -> FlowExecutionStatus. Anything other than\n // COMPLETED/FAILED collapses to UNKNOWN → evaluator returns\n // null → flow ends.\n const flowStatus: FlowExecutionStatus =\n result.status === StepStatus.COMPLETED\n ? FlowExecutionStatus.COMPLETED\n : result.status === StepStatus.FAILED\n ? FlowExecutionStatus.FAILED\n : FlowExecutionStatus.UNKNOWN;\n const deciderExitStatus = await this.resolveDeciderExitStatus(\n jobDef,\n currentStepId,\n {\n jobExecution: execution,\n stepId: step.id,\n stepExecutionId: stepExecution.id,\n stepStatus: result.status,\n exitCode: result.exitCode,\n exitMessage: result.exitMessage,\n },\n );\n const flowExitStatus = deciderExitStatus ?? (result.exitCode || flowStatus);\n\n let evaluatorResult = await this.flowEvaluator.evaluate(\n jobDef.transitions,\n currentStepId,\n flowExitStatus,\n );\n\n // Distinguish \"no transition declared\" (linear fallback) from\n // \"transition declared with toStepId: null\" (explicit END).\n // FlowEvaluator returns null for both, so we inspect the\n // transition list directly.\n let hasMatchingTransition = jobDef.transitions.some((t) =>\n this.flowEvaluator.matches(t, currentStepId!, flowExitStatus),\n );\n if (!hasMatchingTransition && flowExitStatus !== flowStatus) {\n evaluatorResult = await this.flowEvaluator.evaluate(\n jobDef.transitions,\n currentStepId,\n flowStatus,\n );\n hasMatchingTransition = jobDef.transitions.some((t) =>\n this.flowEvaluator.matches(t, currentStepId!, flowStatus),\n );\n }\n\n let nextStepId: string | null;\n if (hasMatchingTransition) {\n // Explicit transition: respect its target, including null\n // (END). Do not fall through to linear order.\n nextStepId = evaluatorResult;\n } else if (result.status === StepStatus.FAILED) {\n // FAILED with no matching transition → short-circuit. The\n // graph declares no path forward, so the job is FAILED — we\n // must not invent a \"next\" step.\n await this.repository.updateJobExecution(execution.id, {\n status: JobStatus.FAILED,\n endTime: new Date(),\n exitCode: result.exitCode,\n exitMessage: result.exitMessage,\n });\n finalStatus = JobStatus.FAILED;\n break;\n } else {\n // COMPLETED with no transition → linear fallback to the next\n // step in declaration order. If we're already on the last\n // step, the job ends.\n const currentIdx = stepOrder.indexOf(currentStepId);\n const nextIdx = currentIdx + 1;\n nextStepId = nextIdx < stepOrder.length ? stepOrder[nextIdx]! : null;\n }\n\n currentStepId = nextStepId;\n }\n\n if (finalStatus === JobStatus.COMPLETED) {\n await this.repository.updateJobExecution(execution.id, {\n status: JobStatus.COMPLETED,\n endTime: new Date(),\n exitCode: 'COMPLETED',\n });\n }\n } catch (err) {\n // Defensive: leave the job FAILED rather than crash the host.\n await this.repository.updateJobExecution(execution.id, {\n status: JobStatus.FAILED,\n endTime: new Date(),\n exitMessage: err instanceof Error ? err.message : String(err),\n });\n finalStatus = JobStatus.FAILED;\n }\n\n // `after:job:*` listeners run once the job is in a terminal state.\n // They receive the final status as the second positional argument\n // (the `args` slot in the current API; the legacy builder path used\n // the same shape). The resolver map is the same one built above;\n // we re-use it to avoid a second IR walk.\n await this.listenerInvoker.invokeAfter(\n jobResolvers,\n 'job',\n { jobExecutionId: execution.id, stepExecutionId: '<job>' },\n [{ status: finalStatus }],\n );\n\n await this.emit({\n type:\n finalStatus === JobStatus.COMPLETED ? BATCH_EVENT.JOB_COMPLETED : BATCH_EVENT.JOB_FAILED,\n timestamp: new Date(),\n jobExecutionId: execution.id,\n data: { status: finalStatus },\n });\n\n return (await this.repository.getJobExecution(execution.id))!;\n }\n\n /**\n * Build a listener resolver map for the given job. Walks every\n * `ListenerDefinition` in `jobDef.listeners` (job-level + step-level +\n * chunk-level + item-level + skip-level) and resolves each ref into a\n * callable `ListenerEntry` keyed by `${phase}:${kind}:${name}`.\n *\n * The returned map is consumed by `ListenerInvoker.invokeBefore /\n * invokeAfter / invokeOnError / invokeOnSkip*` (Task 20 API). The legacy\n * step-level methods (`invokeBeforeStep` etc.) consume a derived\n * legacy-shaped map produced by `buildLegacyStepResolvers` — that\n * conversion happens at the call site, not here, so this method stays\n * the single source of truth for the new shape.\n *\n * Ref resolution rules:\n * - `RefKind.BuilderLambda` → use `ref.fn` directly (the compiler\n * pre-binds decorator-discovered methods\n * and the builder API ships bare fns).\n * - `RefKind.Method` → requires the Jobable instance. Until\n * a `ModuleRef` is wired (Task 9+), this\n * branch logs a warning and is skipped.\n * - `RefKind.ProviderToken` → resolved in Task 9 against a\n * pre-built provider map. Skipped here\n * with a warning.\n */\n private buildResolverMap(jobDef: JobDefinition): ResolverMap {\n const resolvers: ResolverMap = new Map();\n let lambdaCounter = 0;\n\n for (const def of jobDef.listeners) {\n const fn = this.resolveListenerRef(def);\n if (fn === null) continue;\n\n const name = this.resolveListenerName(def.ref, lambdaCounter);\n if (def.ref.kind === RefKind.BuilderLambda) lambdaCounter += 1;\n\n const key = `${def.phase}:${def.kind}:${name}`;\n resolvers.set(key, {\n fn,\n ...(def.nonCritical !== undefined ? { nonCritical: def.nonCritical } : {}),\n });\n }\n\n return resolvers;\n }\n\n /**\n * Resolve a single `ListenerDefinition` to its callable function, or\n * `null` if the ref kind is not yet supported. See `buildResolverMap`\n * for the per-kind resolution contract.\n */\n private resolveListenerRef(def: ListenerDefinition): ((...args: any[]) => any) | null {\n const ref = def.ref;\n switch (ref.kind) {\n case RefKind.BuilderLambda:\n return ref.fn ?? null;\n case RefKind.Method:\n this.logger.warn(\n `JobExecutor: Method-ref listener (classToken=${ref.classToken ?? '<unknown>'}, ` +\n `methodName=${ref.methodName ?? '<unknown>'}) requires a Jobable instance; ` +\n 'this resolution path lands in a follow-up task. Listener skipped.',\n );\n return null;\n case RefKind.ProviderToken:\n this.logger.warn(\n `JobExecutor: ProviderToken-ref listener (token=${ref.token ?? '<empty>'}) ` +\n 'is resolved in Task 9. Listener skipped.',\n );\n return null;\n default: {\n const _exhaustive: never = ref.kind;\n void _exhaustive;\n return null;\n }\n }\n }\n\n /**\n * Derive the `name` segment of the resolver key. Method refs carry a\n * `classToken` + `methodName` pair that uniquely identifies the bound\n * method; BuilderLambda refs do not carry a name (the compiler drops\n * the method name when it pre-binds), so we mint a `lambda-N` name\n * from a per-job counter to guarantee uniqueness.\n */\n private resolveListenerName(ref: ListenerRef, lambdaCounter: number): string {\n if (ref.kind === RefKind.Method) {\n return `${ref.classToken ?? '<unknown>'}.${ref.methodName ?? '<unknown>'}`;\n }\n return `lambda-${lambdaCounter}`;\n }\n\n /**\n * Derive a legacy `Map<string, ListenerResolver>` from a new\n * `ResolverMap`, containing only the step-level entries with their\n * keys translated from `${phase}:step:${name}` back to the legacy\n * `${phase}-step:${name}` shape. The `nonCritical` flag is dropped\n * (legacy `ListenerResolver` is a bare function with no metadata).\n *\n * This is the bridge the `TaskletStepExecutor` (which still consumes\n * the legacy shape) needs until it migrates to the new API. Kept as\n * a private helper so the conversion logic is in one place.\n */\n private buildLegacyStepResolvers(resolvers: ResolverMap): Map<string, ListenerResolver> {\n const legacy: Map<string, ListenerResolver> = new Map();\n for (const [key, entry] of resolvers.entries()) {\n if (key.startsWith('before:step:')) {\n legacy.set(`before-step:${key.slice('before:step:'.length)}`, entry.fn as ListenerResolver);\n } else if (key.startsWith('after:step:')) {\n legacy.set(`after-step:${key.slice('after:step:'.length)}`, entry.fn as ListenerResolver);\n } else if (key.startsWith('on-error:step:')) {\n legacy.set(`on-step-error:${key.slice('on-error:step:'.length)}`, entry.fn as ListenerResolver);\n }\n }\n return legacy;\n }\n\n /**\n * Read the `lastChunkIndex` checkpoint from the step-scoped\n * ExecutionContext for `stepExecutionId`. Returns `undefined` when the\n * step has no recorded checkpoint (e.g., the prior run failed on the\n * very first chunk and never got a chance to write one). The chunk\n * executor treats `undefined` as \"no resume; start from the beginning\".\n */\n private async getLastCheckpoint(stepExecutionId: string): Promise<number | undefined> {\n const ctx = await this.repository.getExecutionContext({ stepExecutionId });\n if (ctx.data === null || typeof ctx.data !== 'object' || Array.isArray(ctx.data)) {\n return undefined;\n }\n const value = (ctx.data as { lastChunkIndex?: unknown }).lastChunkIndex;\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n }\n\n private async resolveDeciderExitStatus(\n jobDef: JobDefinition,\n afterStepId: string,\n context: Parameters<NonNullable<JobDefinition['deciders']>[number]['decide']>[0],\n ): Promise<string | undefined> {\n const decider = (jobDef.deciders ?? []).find((d) => d.afterStepId === afterStepId);\n if (decider === undefined) return undefined;\n const status = await decider.decide(context);\n const trimmed = status.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n\n /**\n * Dispatch a BatchEvent to the configured observer. Errors thrown by\n * the observer are swallowed: a failing logger/queue must not crash\n * the executor (the job's persisted state is the source of truth).\n */\n private async emit(event: BatchEvent): Promise<void> {\n try {\n await this.observer.onEvent(event);\n } catch {\n // intentional: observer failures are best-effort and must not\n // affect the executor's own state transitions.\n }\n }\n}\n\n// Re-export common types for convenience so callers that import\n// `JobExecutor` don't need a second import for `StepExecutionResult` etc.\nexport type { StepExecutionResult } from './tasklet-step-executor';\nexport type { ChunkExecutionResult } from './chunk-step-executor';\nexport type { JobParameters, JobExecution };\n"],"names":["JobExecutor","logger","Logger","name","repository","transactionManager","taskletExecutor","chunkExecutor","listenerInvoker","flowEvaluator","observer","NoopBatchObserver","execute","execution","jobDef","partition","isRestart","status","JobStatus","FAILED","STOPPED","restartable","JobNotRestartableError","id","updateJobExecution","STARTED","startTime","Date","emit","type","BATCH_EVENT","JOB_STARTED","timestamp","jobExecutionId","data","jobName","jobResolvers","buildResolverMap","stepResolvers","buildLegacyStepResolvers","invokeBefore","stepExecutionId","stepOrder","Object","keys","steps","currentStepId","startStepId","finalStatus","COMPLETED","currentStepExecutionId","step","endTime","exitCode","exitMessage","resumeFromChunkIndex","kind","priorFailed","findLatestStepExecution","StepStatus","getLastCheckpoint","stepExecution","createStepExecution","STEP_STARTED","stepId","result","jobRepository","listenerResolvers","partitionArgs","partitionIndex","undefined","partitionCount","jobExecutionId2","resolvers","Map","stepErr","updateStepExecution","Error","message","String","readCount","writeCount","skipCount","commitCount","STEP_COMPLETED","STEP_FAILED","flowStatus","FlowExecutionStatus","UNKNOWN","deciderExitStatus","resolveDeciderExitStatus","jobExecution","stepStatus","flowExitStatus","evaluatorResult","evaluate","transitions","hasMatchingTransition","some","t","matches","nextStepId","currentIdx","indexOf","nextIdx","length","err","invokeAfter","JOB_COMPLETED","JOB_FAILED","getJobExecution","lambdaCounter","def","listeners","fn","resolveListenerRef","resolveListenerName","ref","RefKind","BuilderLambda","key","phase","set","nonCritical","Method","warn","classToken","methodName","ProviderToken","token","_exhaustive","legacy","entry","entries","startsWith","slice","ctx","getExecutionContext","Array","isArray","value","lastChunkIndex","Number","isFinite","afterStepId","context","decider","deciders","find","d","decide","trimmed","trim","event","onEvent","TransactionManager"],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { JobDefinition } from '../core/ir';
2
+ import { JobExecutionDetails, JobExecutionFilter, JobInstance, JobInstanceFilter, JobExecution } from '../core/repository';
3
+ import { JobRepository } from '../core/repository';
4
+ import { JobRegistry } from '../registry/job-registry';
5
+ export declare class JobExplorer {
6
+ private readonly registry;
7
+ private readonly repository;
8
+ constructor(registry: JobRegistry, repository: JobRepository);
9
+ listJobs(): JobDefinition[];
10
+ getJobInstance(jobInstanceId: string): Promise<JobInstance>;
11
+ listJobInstances(filter?: JobInstanceFilter): Promise<JobInstance[]>;
12
+ listJobExecutions(filter?: JobExecutionFilter): Promise<JobExecution[]>;
13
+ getJobExecutionDetails(executionId: string): Promise<JobExecutionDetails>;
14
+ }
15
+ //# sourceMappingURL=job-explorer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-explorer.d.ts","sourceRoot":"","sources":["../../../src/execution/job-explorer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,YAAY,EACb,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAKnD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,qBACa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;gBADV,QAAQ,EAAE,WAAW,EACrB,UAAU,EAAE,aAAa;IAG5C,QAAQ,IAAI,aAAa,EAAE;IAIrB,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAQ3D,gBAAgB,CAAC,MAAM,GAAE,iBAAsB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAIxE,iBAAiB,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI3E,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;CA4BhF"}
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "JobExplorer", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return JobExplorer;
9
+ }
10
+ });
11
+ const _common = require("@nestjs/common");
12
+ const _repository = require("../core/repository");
13
+ const _errors = require("../core/errors");
14
+ const _jobregistry = require("../registry/job-registry");
15
+ function _ts_decorate(decorators, target, key, desc) {
16
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
17
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
18
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
19
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
20
+ }
21
+ function _ts_metadata(k, v) {
22
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
23
+ }
24
+ let JobExplorer = class JobExplorer {
25
+ registry;
26
+ repository;
27
+ constructor(registry, repository){
28
+ this.registry = registry;
29
+ this.repository = repository;
30
+ }
31
+ listJobs() {
32
+ return this.registry.getAll();
33
+ }
34
+ async getJobInstance(jobInstanceId) {
35
+ const instance = await this.repository.getJobInstance(jobInstanceId);
36
+ if (instance === null) {
37
+ throw new _errors.JobInstanceNotFoundError(jobInstanceId);
38
+ }
39
+ return instance;
40
+ }
41
+ async listJobInstances(filter = {}) {
42
+ return this.repository.findJobInstances(filter);
43
+ }
44
+ async listJobExecutions(filter = {}) {
45
+ return this.repository.findJobExecutions(filter);
46
+ }
47
+ async getJobExecutionDetails(executionId) {
48
+ const jobExecution = await this.repository.getJobExecution(executionId);
49
+ if (jobExecution === null) {
50
+ throw new _errors.JobExecutionNotFoundError(executionId);
51
+ }
52
+ const jobInstance = await this.repository.getJobInstance(jobExecution.jobInstanceId);
53
+ if (jobInstance === null) {
54
+ throw new _errors.JobInstanceNotFoundError(jobExecution.jobInstanceId);
55
+ }
56
+ const stepExecutions = await this.repository.findStepExecutions(executionId);
57
+ const jobContext = await this.repository.getExecutionContext({
58
+ jobExecutionId: executionId
59
+ });
60
+ const stepContexts = await Promise.all(stepExecutions.map(async (step)=>({
61
+ stepExecutionId: step.id,
62
+ context: await this.repository.getExecutionContext({
63
+ stepExecutionId: step.id
64
+ })
65
+ })));
66
+ return {
67
+ jobInstance,
68
+ jobExecution,
69
+ stepExecutions,
70
+ jobContext,
71
+ stepContexts
72
+ };
73
+ }
74
+ };
75
+ JobExplorer = _ts_decorate([
76
+ (0, _common.Injectable)(),
77
+ _ts_metadata("design:type", Function),
78
+ _ts_metadata("design:paramtypes", [
79
+ typeof _jobregistry.JobRegistry === "undefined" ? Object : _jobregistry.JobRegistry,
80
+ typeof _repository.JobRepository === "undefined" ? Object : _repository.JobRepository
81
+ ])
82
+ ], JobExplorer);
83
+
84
+ //# sourceMappingURL=job-explorer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/execution/job-explorer.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\n\nimport type { JobDefinition } from '../core/ir';\nimport {\n JobExecutionDetails,\n JobExecutionFilter,\n JobInstance,\n JobInstanceFilter,\n JobExecution,\n} from '../core/repository';\nimport { JobRepository } from '../core/repository';\nimport {\n JobExecutionNotFoundError,\n JobInstanceNotFoundError,\n} from '../core/errors';\nimport { JobRegistry } from '../registry/job-registry';\n\n@Injectable()\nexport class JobExplorer {\n constructor(\n private readonly registry: JobRegistry,\n private readonly repository: JobRepository,\n ) {}\n\n listJobs(): JobDefinition[] {\n return this.registry.getAll();\n }\n\n async getJobInstance(jobInstanceId: string): Promise<JobInstance> {\n const instance = await this.repository.getJobInstance(jobInstanceId);\n if (instance === null) {\n throw new JobInstanceNotFoundError(jobInstanceId);\n }\n return instance;\n }\n\n async listJobInstances(filter: JobInstanceFilter = {}): Promise<JobInstance[]> {\n return this.repository.findJobInstances(filter);\n }\n\n async listJobExecutions(filter: JobExecutionFilter = {}): Promise<JobExecution[]> {\n return this.repository.findJobExecutions(filter);\n }\n\n async getJobExecutionDetails(executionId: string): Promise<JobExecutionDetails> {\n const jobExecution = await this.repository.getJobExecution(executionId);\n if (jobExecution === null) {\n throw new JobExecutionNotFoundError(executionId);\n }\n\n const jobInstance = await this.repository.getJobInstance(jobExecution.jobInstanceId);\n if (jobInstance === null) {\n throw new JobInstanceNotFoundError(jobExecution.jobInstanceId);\n }\n\n const stepExecutions = await this.repository.findStepExecutions(executionId);\n const jobContext = await this.repository.getExecutionContext({ jobExecutionId: executionId });\n const stepContexts = await Promise.all(\n stepExecutions.map(async (step) => ({\n stepExecutionId: step.id,\n context: await this.repository.getExecutionContext({ stepExecutionId: step.id }),\n })),\n );\n\n return {\n jobInstance,\n jobExecution,\n stepExecutions,\n jobContext,\n stepContexts,\n };\n }\n}\n"],"names":["JobExplorer","registry","repository","listJobs","getAll","getJobInstance","jobInstanceId","instance","JobInstanceNotFoundError","listJobInstances","filter","findJobInstances","listJobExecutions","findJobExecutions","getJobExecutionDetails","executionId","jobExecution","getJobExecution","JobExecutionNotFoundError","jobInstance","stepExecutions","findStepExecutions","jobContext","getExecutionContext","jobExecutionId","stepContexts","Promise","all","map","step","stepExecutionId","id","context"],"mappings":";;;;+BAkBaA;;;eAAAA;;;wBAlBc;4BAUG;wBAIvB;6BACqB;;;;;;;;;;AAGrB,IAAA,AAAMA,cAAN,MAAMA;;;IACX,YACE,AAAiBC,QAAqB,EACtC,AAAiBC,UAAyB,CAC1C;aAFiBD,WAAAA;aACAC,aAAAA;IAChB;IAEHC,WAA4B;QAC1B,OAAO,IAAI,CAACF,QAAQ,CAACG,MAAM;IAC7B;IAEA,MAAMC,eAAeC,aAAqB,EAAwB;QAChE,MAAMC,WAAW,MAAM,IAAI,CAACL,UAAU,CAACG,cAAc,CAACC;QACtD,IAAIC,aAAa,MAAM;YACrB,MAAM,IAAIC,gCAAwB,CAACF;QACrC;QACA,OAAOC;IACT;IAEA,MAAME,iBAAiBC,SAA4B,CAAC,CAAC,EAA0B;QAC7E,OAAO,IAAI,CAACR,UAAU,CAACS,gBAAgB,CAACD;IAC1C;IAEA,MAAME,kBAAkBF,SAA6B,CAAC,CAAC,EAA2B;QAChF,OAAO,IAAI,CAACR,UAAU,CAACW,iBAAiB,CAACH;IAC3C;IAEA,MAAMI,uBAAuBC,WAAmB,EAAgC;QAC9E,MAAMC,eAAe,MAAM,IAAI,CAACd,UAAU,CAACe,eAAe,CAACF;QAC3D,IAAIC,iBAAiB,MAAM;YACzB,MAAM,IAAIE,iCAAyB,CAACH;QACtC;QAEA,MAAMI,cAAc,MAAM,IAAI,CAACjB,UAAU,CAACG,cAAc,CAACW,aAAaV,aAAa;QACnF,IAAIa,gBAAgB,MAAM;YACxB,MAAM,IAAIX,gCAAwB,CAACQ,aAAaV,aAAa;QAC/D;QAEA,MAAMc,iBAAiB,MAAM,IAAI,CAAClB,UAAU,CAACmB,kBAAkB,CAACN;QAChE,MAAMO,aAAa,MAAM,IAAI,CAACpB,UAAU,CAACqB,mBAAmB,CAAC;YAAEC,gBAAgBT;QAAY;QAC3F,MAAMU,eAAe,MAAMC,QAAQC,GAAG,CACpCP,eAAeQ,GAAG,CAAC,OAAOC,OAAU,CAAA;gBAClCC,iBAAiBD,KAAKE,EAAE;gBACxBC,SAAS,MAAM,IAAI,CAAC9B,UAAU,CAACqB,mBAAmB,CAAC;oBAAEO,iBAAiBD,KAAKE,EAAE;gBAAC;YAChF,CAAA;QAGF,OAAO;YACLZ;YACAH;YACAI;YACAE;YACAG;QACF;IACF;AACF"}
@@ -0,0 +1,3 @@
1
+ import type { JobParameters } from '../core/repository/types';
2
+ export declare function canonicalJobKey(params: JobParameters): string;
3
+ //# sourceMappingURL=job-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-key.d.ts","sourceRoot":"","sources":["../../../src/execution/job-key.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA6B9D,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAI7D"}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "canonicalJobKey", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return canonicalJobKey;
9
+ }
10
+ });
11
+ const _crypto = require("crypto");
12
+ /**
13
+ * Canonicalize JobParameters into a stable string.
14
+ * - Object keys sorted alphabetically (recursive)
15
+ * - Arrays preserve order (different order = different key)
16
+ * - Date → ISO string
17
+ * - null/undefined → omitted
18
+ * - Number: keep as-is (1 vs 1.0 same via String())
19
+ * - String: as-is (no whitespace trim — callers must normalize)
20
+ */ function canonicalize(value) {
21
+ if (value === null || value === undefined) return undefined;
22
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return value;
23
+ if (typeof value === 'bigint') throw new Error('BigInt not supported in job key');
24
+ if (value instanceof Date) return value.toISOString();
25
+ if (Array.isArray(value)) return value.map(canonicalize);
26
+ if (typeof value === 'object') {
27
+ const obj = value;
28
+ const sorted = {};
29
+ for (const k of Object.keys(obj).sort()){
30
+ const v = canonicalize(obj[k]);
31
+ if (v !== undefined) sorted[k] = v;
32
+ }
33
+ return sorted;
34
+ }
35
+ return value;
36
+ }
37
+ function canonicalJobKey(params) {
38
+ const canonical = canonicalize(params);
39
+ const json = JSON.stringify(canonical);
40
+ return (0, _crypto.createHash)('sha256').update(json).digest('hex');
41
+ }
42
+
43
+ //# sourceMappingURL=job-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/execution/job-key.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport type { JobParameters } from '../core/repository/types';\n\n/**\n * Canonicalize JobParameters into a stable string.\n * - Object keys sorted alphabetically (recursive)\n * - Arrays preserve order (different order = different key)\n * - Date → ISO string\n * - null/undefined → omitted\n * - Number: keep as-is (1 vs 1.0 same via String())\n * - String: as-is (no whitespace trim — callers must normalize)\n */\nfunction canonicalize(value: unknown): unknown {\n if (value === null || value === undefined) return undefined;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return value;\n if (typeof value === 'bigint') throw new Error('BigInt not supported in job key');\n if (value instanceof Date) return value.toISOString();\n if (Array.isArray(value)) return value.map(canonicalize);\n if (typeof value === 'object') {\n const obj = value as Record<string, unknown>;\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(obj).sort()) {\n const v = canonicalize(obj[k]);\n if (v !== undefined) sorted[k] = v;\n }\n return sorted;\n }\n return value;\n}\n\nexport function canonicalJobKey(params: JobParameters): string {\n const canonical = canonicalize(params);\n const json = JSON.stringify(canonical);\n return createHash('sha256').update(json).digest('hex');\n}\n"],"names":["canonicalJobKey","canonicalize","value","undefined","Error","Date","toISOString","Array","isArray","map","obj","sorted","k","Object","keys","sort","v","params","canonical","json","JSON","stringify","createHash","update","digest"],"mappings":";;;;+BA8BgBA;;;eAAAA;;;wBA9BW;AAG3B;;;;;;;;CAQC,GACD,SAASC,aAAaC,KAAc;IAClC,IAAIA,UAAU,QAAQA,UAAUC,WAAW,OAAOA;IAClD,IAAI,OAAOD,UAAU,YAAY,OAAOA,UAAU,YAAY,OAAOA,UAAU,WAAW,OAAOA;IACjG,IAAI,OAAOA,UAAU,UAAU,MAAM,IAAIE,MAAM;IAC/C,IAAIF,iBAAiBG,MAAM,OAAOH,MAAMI,WAAW;IACnD,IAAIC,MAAMC,OAAO,CAACN,QAAQ,OAAOA,MAAMO,GAAG,CAACR;IAC3C,IAAI,OAAOC,UAAU,UAAU;QAC7B,MAAMQ,MAAMR;QACZ,MAAMS,SAAkC,CAAC;QACzC,KAAK,MAAMC,KAAKC,OAAOC,IAAI,CAACJ,KAAKK,IAAI,GAAI;YACvC,MAAMC,IAAIf,aAAaS,GAAG,CAACE,EAAE;YAC7B,IAAII,MAAMb,WAAWQ,MAAM,CAACC,EAAE,GAAGI;QACnC;QACA,OAAOL;IACT;IACA,OAAOT;AACT;AAEO,SAASF,gBAAgBiB,MAAqB;IACnD,MAAMC,YAAYjB,aAAagB;IAC/B,MAAME,OAAOC,KAAKC,SAAS,CAACH;IAC5B,OAAOI,IAAAA,kBAAU,EAAC,UAAUC,MAAM,CAACJ,MAAMK,MAAM,CAAC;AAClD"}
@@ -0,0 +1,75 @@
1
+ import { JobRepository, type JobParameters, type JobExecution } from '../core/repository';
2
+ import { JobRegistry } from '../registry/job-registry';
3
+ import { type IExecutionStrategy } from './execution-strategy';
4
+ import { JobExecutor } from './job-executor';
5
+ import type { JobDefinition } from '../core/ir';
6
+ /**
7
+ * JobLauncher — public entry point for starting a new JobExecution.
8
+ *
9
+ * Flow (pre-strategy, kept unchanged for backwards compat):
10
+ * 1. Look up the `JobDefinition` from the registry. Missing → `JobNotFoundError`.
11
+ * 2. Canonicalize `params` into a stable `jobKey` hash. Object key order,
12
+ * `null/undefined` omission, `Date → ISO` are all normalized so that
13
+ * semantically-identical params yield the same key.
14
+ * 3. `createExecutionAtomic(jobId, jobKey, params)` — idempotent
15
+ * instance get-or-create + `SELECT ... FOR UPDATE SKIP LOCKED` to
16
+ * serialize concurrent launches + running-execution check + insert,
17
+ * all in a single transaction. Throws
18
+ * `JobExecutionAlreadyRunningError` if another launch is in flight
19
+ * or an execution is already STARTING/STARTED for the same instance.
20
+ * 4. Delegate to the injected `IExecutionStrategy` (default:
21
+ * `InProcessExecutionStrategy`, which wraps `JobExecutor.execute`).
22
+ * The lock is released when the createExecutionAtomic transaction
23
+ * commits; the executor itself runs outside the lock (it can be
24
+ * long-running).
25
+ *
26
+ * `allowDuplicateInstances: true` bypasses step 2's dedup by appending a
27
+ * fresh UUID nonce to the canonical key on every call, forcing a new
28
+ * `JobInstance` each time.
29
+ *
30
+ * Polymorphic strategy (Task 11):
31
+ * The launcher is a thin facade — it owns the registry lookup, the
32
+ * canonical `jobKey` derivation, the atomic instance + concurrency
33
+ * lock, and the post-strategy `JobExecution` re-resolution. The
34
+ * actual *how* of running the job (in-process vs. transport) lives
35
+ * behind the `EXECUTION_STRATEGY` token. Sibling packages (e.g.
36
+ * `@nest-batch/bullmq`) override the token with a transport
37
+ * strategy that enqueues work; the launcher never learns about the
38
+ * transport.
39
+ *
40
+ * When no strategy is bound (e.g. direct manual construction in
41
+ * unit tests), the launcher falls back to the original direct
42
+ * `JobExecutor.execute` path. This keeps the legacy
43
+ * `tests/execution/job-launcher.test.ts` working without changes.
44
+ */
45
+ export declare class JobLauncher {
46
+ private readonly registry;
47
+ private readonly repository;
48
+ private readonly jobExecutor;
49
+ private readonly strategy?;
50
+ constructor(registry: JobRegistry, repository: JobRepository, jobExecutor: JobExecutor, strategy?: IExecutionStrategy | undefined);
51
+ /**
52
+ * Launch a new job execution. Returns the final `JobExecution` after it
53
+ * has finished (status = COMPLETED | FAILED) — or, for transport
54
+ * strategies that return `{ kind: 'enqueued' }`, the latest persisted
55
+ * `JobExecution` (still in `STARTING` / `STARTED`, since the executor
56
+ * has not run on the launcher process).
57
+ *
58
+ * Throws `JobNotFoundError` if `jobId` is not registered.
59
+ * Throws `JobExecutionAlreadyRunningError` if a previous launch of the
60
+ * same `jobName + jobKey` is still in flight.
61
+ */
62
+ launch(jobId: string, params?: JobParameters): Promise<JobExecution>;
63
+ /**
64
+ * Resume an existing `JobExecution` (used by the restart path).
65
+ * For this MVP it just delegates to the executor — the launcher does
66
+ * not yet gate on restartable / concurrency / FAILED-prev-exists rules.
67
+ *
68
+ * Note: `run` bypasses the strategy on purpose. Restart is a
69
+ * recovery path on the in-process execution model; transport
70
+ * strategies that need their own resume semantics can override
71
+ * this method on a subclass or via a future token.
72
+ */
73
+ run(execution: JobExecution, jobDef: JobDefinition): Promise<JobExecution>;
74
+ }
75
+ //# sourceMappingURL=job-launcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-launcher.d.ts","sourceRoot":"","sources":["../../../src/execution/job-launcher.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC1F,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAIhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AACH,qBACa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAG5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;gBANT,QAAQ,EAAE,WAAW,EACrB,UAAU,EAAE,aAAa,EAEzB,WAAW,EAAE,WAAW,EAGxB,QAAQ,CAAC,EAAE,kBAAkB,YAAA;IAGhD;;;;;;;;;;OAUG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAqC9E;;;;;;;;;OASG;IACG,GAAG,CAAC,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CAGjF"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "JobLauncher", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return JobLauncher;
9
+ }
10
+ });
11
+ const _crypto = require("crypto");
12
+ const _common = require("@nestjs/common");
13
+ const _repository = require("../core/repository");
14
+ const _jobregistry = require("../registry/job-registry");
15
+ const _executionstrategy = require("./execution-strategy");
16
+ const _jobexecutor = require("./job-executor");
17
+ const _jobkey = require("./job-key");
18
+ function _ts_decorate(decorators, target, key, desc) {
19
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
20
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
21
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
22
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
23
+ }
24
+ function _ts_metadata(k, v) {
25
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
26
+ }
27
+ function _ts_param(paramIndex, decorator) {
28
+ return function(target, key) {
29
+ decorator(target, key, paramIndex);
30
+ };
31
+ }
32
+ let JobLauncher = class JobLauncher {
33
+ registry;
34
+ repository;
35
+ jobExecutor;
36
+ strategy;
37
+ constructor(registry, repository, jobExecutor, strategy){
38
+ this.registry = registry;
39
+ this.repository = repository;
40
+ this.jobExecutor = jobExecutor;
41
+ this.strategy = strategy;
42
+ }
43
+ /**
44
+ * Launch a new job execution. Returns the final `JobExecution` after it
45
+ * has finished (status = COMPLETED | FAILED) — or, for transport
46
+ * strategies that return `{ kind: 'enqueued' }`, the latest persisted
47
+ * `JobExecution` (still in `STARTING` / `STARTED`, since the executor
48
+ * has not run on the launcher process).
49
+ *
50
+ * Throws `JobNotFoundError` if `jobId` is not registered.
51
+ * Throws `JobExecutionAlreadyRunningError` if a previous launch of the
52
+ * same `jobName + jobKey` is still in flight.
53
+ */ async launch(jobId, params = {}) {
54
+ const jobDef = this.registry.get(jobId); // throws JobNotFoundError on miss
55
+ const canonical = (0, _jobkey.canonicalJobKey)(params);
56
+ const jobKey = jobDef.allowDuplicateInstances ? `${canonical}::${(0, _crypto.randomUUID)()}` : canonical;
57
+ // Atomic get-or-create + lock + check + insert. The repository's
58
+ // implementation uses INSERT ... ON CONFLICT DO NOTHING +
59
+ // FOR UPDATE SKIP LOCKED to serialize concurrent launches.
60
+ const execution = await this.repository.createExecutionAtomic(jobId, jobKey, params);
61
+ // No strategy bound → fall back to the legacy direct-execute path.
62
+ // This branch preserves `tests/execution/job-launcher.test.ts` (which
63
+ // wires the launcher by hand, no Nest module) and any other
64
+ // direct-construction consumer.
65
+ if (this.strategy === undefined) {
66
+ return this.jobExecutor.execute(execution, jobDef);
67
+ }
68
+ // The strategy's `LaunchResult` is intentionally discarded: the
69
+ // public `JobLauncher.launch` contract always returns a
70
+ // `JobExecution` (re-resolved from the repository below), and
71
+ // `queueJobId` is for the strategy's own bookkeeping only.
72
+ await this.strategy.launch(jobDef, params, {
73
+ executionId: execution.id,
74
+ jobExecutionId: execution.id
75
+ });
76
+ // For both `completed` and `enqueued` the public `JobLauncher.launch`
77
+ // contract returns a `JobExecution`. Re-resolve the latest persisted
78
+ // row so the caller sees the executor's writes (status, endTime,
79
+ // exitCode) without us hand-merging patches here. If the lookup
80
+ // somehow returns null (e.g. a custom repository that drops rows),
81
+ // fall back to the execution the launcher pre-created.
82
+ const latest = await this.repository.getJobExecution(execution.id);
83
+ return latest ?? execution;
84
+ }
85
+ /**
86
+ * Resume an existing `JobExecution` (used by the restart path).
87
+ * For this MVP it just delegates to the executor — the launcher does
88
+ * not yet gate on restartable / concurrency / FAILED-prev-exists rules.
89
+ *
90
+ * Note: `run` bypasses the strategy on purpose. Restart is a
91
+ * recovery path on the in-process execution model; transport
92
+ * strategies that need their own resume semantics can override
93
+ * this method on a subclass or via a future token.
94
+ */ async run(execution, jobDef) {
95
+ return this.jobExecutor.execute(execution, jobDef);
96
+ }
97
+ };
98
+ JobLauncher = _ts_decorate([
99
+ (0, _common.Injectable)(),
100
+ _ts_param(2, (0, _common.Inject)((0, _common.forwardRef)(()=>_jobexecutor.JobExecutor))),
101
+ _ts_param(3, (0, _common.Optional)()),
102
+ _ts_param(3, (0, _common.Inject)(_executionstrategy.EXECUTION_STRATEGY)),
103
+ _ts_metadata("design:type", Function),
104
+ _ts_metadata("design:paramtypes", [
105
+ typeof _jobregistry.JobRegistry === "undefined" ? Object : _jobregistry.JobRegistry,
106
+ typeof _repository.JobRepository === "undefined" ? Object : _repository.JobRepository,
107
+ typeof _jobexecutor.JobExecutor === "undefined" ? Object : _jobexecutor.JobExecutor,
108
+ typeof IExecutionStrategy === "undefined" ? Object : IExecutionStrategy
109
+ ])
110
+ ], JobLauncher);
111
+
112
+ //# sourceMappingURL=job-launcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/execution/job-launcher.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\n\nimport { Inject, Injectable, Optional, forwardRef } from '@nestjs/common';\n\nimport { JobNotFoundError, JobExecutionAlreadyRunningError } from '../core/errors';\nimport { JobRepository, type JobParameters, type JobExecution } from '../core/repository';\nimport { JobRegistry } from '../registry/job-registry';\n\nimport {\n EXECUTION_STRATEGY,\n type IExecutionStrategy,\n} from './execution-strategy';\nimport { JobExecutor } from './job-executor';\nimport { canonicalJobKey } from './job-key';\n\nimport type { JobDefinition } from '../core/ir';\n\n\n\n/**\n * JobLauncher — public entry point for starting a new JobExecution.\n *\n * Flow (pre-strategy, kept unchanged for backwards compat):\n * 1. Look up the `JobDefinition` from the registry. Missing → `JobNotFoundError`.\n * 2. Canonicalize `params` into a stable `jobKey` hash. Object key order,\n * `null/undefined` omission, `Date → ISO` are all normalized so that\n * semantically-identical params yield the same key.\n * 3. `createExecutionAtomic(jobId, jobKey, params)` — idempotent\n * instance get-or-create + `SELECT ... FOR UPDATE SKIP LOCKED` to\n * serialize concurrent launches + running-execution check + insert,\n * all in a single transaction. Throws\n * `JobExecutionAlreadyRunningError` if another launch is in flight\n * or an execution is already STARTING/STARTED for the same instance.\n * 4. Delegate to the injected `IExecutionStrategy` (default:\n * `InProcessExecutionStrategy`, which wraps `JobExecutor.execute`).\n * The lock is released when the createExecutionAtomic transaction\n * commits; the executor itself runs outside the lock (it can be\n * long-running).\n *\n * `allowDuplicateInstances: true` bypasses step 2's dedup by appending a\n * fresh UUID nonce to the canonical key on every call, forcing a new\n * `JobInstance` each time.\n *\n * Polymorphic strategy (Task 11):\n * The launcher is a thin facade — it owns the registry lookup, the\n * canonical `jobKey` derivation, the atomic instance + concurrency\n * lock, and the post-strategy `JobExecution` re-resolution. The\n * actual *how* of running the job (in-process vs. transport) lives\n * behind the `EXECUTION_STRATEGY` token. Sibling packages (e.g.\n * `@nest-batch/bullmq`) override the token with a transport\n * strategy that enqueues work; the launcher never learns about the\n * transport.\n *\n * When no strategy is bound (e.g. direct manual construction in\n * unit tests), the launcher falls back to the original direct\n * `JobExecutor.execute` path. This keeps the legacy\n * `tests/execution/job-launcher.test.ts` working without changes.\n */\n@Injectable()\nexport class JobLauncher {\n constructor(\n private readonly registry: JobRegistry,\n private readonly repository: JobRepository,\n @Inject(forwardRef(() => JobExecutor))\n private readonly jobExecutor: JobExecutor,\n @Optional()\n @Inject(EXECUTION_STRATEGY)\n private readonly strategy?: IExecutionStrategy,\n ) {}\n\n /**\n * Launch a new job execution. Returns the final `JobExecution` after it\n * has finished (status = COMPLETED | FAILED) — or, for transport\n * strategies that return `{ kind: 'enqueued' }`, the latest persisted\n * `JobExecution` (still in `STARTING` / `STARTED`, since the executor\n * has not run on the launcher process).\n *\n * Throws `JobNotFoundError` if `jobId` is not registered.\n * Throws `JobExecutionAlreadyRunningError` if a previous launch of the\n * same `jobName + jobKey` is still in flight.\n */\n async launch(jobId: string, params: JobParameters = {}): Promise<JobExecution> {\n const jobDef = this.registry.get(jobId); // throws JobNotFoundError on miss\n const canonical = canonicalJobKey(params);\n const jobKey = jobDef.allowDuplicateInstances ? `${canonical}::${randomUUID()}` : canonical;\n\n // Atomic get-or-create + lock + check + insert. The repository's\n // implementation uses INSERT ... ON CONFLICT DO NOTHING +\n // FOR UPDATE SKIP LOCKED to serialize concurrent launches.\n const execution = await this.repository.createExecutionAtomic(jobId, jobKey, params);\n\n // No strategy bound → fall back to the legacy direct-execute path.\n // This branch preserves `tests/execution/job-launcher.test.ts` (which\n // wires the launcher by hand, no Nest module) and any other\n // direct-construction consumer.\n if (this.strategy === undefined) {\n return this.jobExecutor.execute(execution, jobDef);\n }\n\n // The strategy's `LaunchResult` is intentionally discarded: the\n // public `JobLauncher.launch` contract always returns a\n // `JobExecution` (re-resolved from the repository below), and\n // `queueJobId` is for the strategy's own bookkeeping only.\n await this.strategy.launch(jobDef, params, {\n executionId: execution.id,\n jobExecutionId: execution.id,\n });\n\n // For both `completed` and `enqueued` the public `JobLauncher.launch`\n // contract returns a `JobExecution`. Re-resolve the latest persisted\n // row so the caller sees the executor's writes (status, endTime,\n // exitCode) without us hand-merging patches here. If the lookup\n // somehow returns null (e.g. a custom repository that drops rows),\n // fall back to the execution the launcher pre-created.\n const latest = await this.repository.getJobExecution(execution.id);\n return latest ?? execution;\n }\n\n /**\n * Resume an existing `JobExecution` (used by the restart path).\n * For this MVP it just delegates to the executor — the launcher does\n * not yet gate on restartable / concurrency / FAILED-prev-exists rules.\n *\n * Note: `run` bypasses the strategy on purpose. Restart is a\n * recovery path on the in-process execution model; transport\n * strategies that need their own resume semantics can override\n * this method on a subclass or via a future token.\n */\n async run(execution: JobExecution, jobDef: JobDefinition): Promise<JobExecution> {\n return this.jobExecutor.execute(execution, jobDef);\n }\n}\n"],"names":["JobLauncher","registry","repository","jobExecutor","strategy","launch","jobId","params","jobDef","get","canonical","canonicalJobKey","jobKey","allowDuplicateInstances","randomUUID","execution","createExecutionAtomic","undefined","execute","executionId","id","jobExecutionId","latest","getJobExecution","run","JobExecutor"],"mappings":";;;;+BA2DaA;;;eAAAA;;;wBA3Dc;wBAE8B;4BAGY;6BACzC;mCAKrB;6BACqB;wBACI;;;;;;;;;;;;;;;AA8CzB,IAAA,AAAMA,cAAN,MAAMA;;;;;IACX,YACE,AAAiBC,QAAqB,EACtC,AAAiBC,UAAyB,EAC1C,AACiBC,WAAwB,EACzC,AAEiBC,QAA6B,CAC9C;aAPiBH,WAAAA;aACAC,aAAAA;aAEAC,cAAAA;aAGAC,WAAAA;IAChB;IAEH;;;;;;;;;;GAUC,GACD,MAAMC,OAAOC,KAAa,EAAEC,SAAwB,CAAC,CAAC,EAAyB;QAC7E,MAAMC,SAAS,IAAI,CAACP,QAAQ,CAACQ,GAAG,CAACH,QAAQ,kCAAkC;QAC3E,MAAMI,YAAYC,IAAAA,uBAAe,EAACJ;QAClC,MAAMK,SAASJ,OAAOK,uBAAuB,GAAG,GAAGH,UAAU,EAAE,EAAEI,IAAAA,kBAAU,KAAI,GAAGJ;QAElF,iEAAiE;QACjE,0DAA0D;QAC1D,2DAA2D;QAC3D,MAAMK,YAAY,MAAM,IAAI,CAACb,UAAU,CAACc,qBAAqB,CAACV,OAAOM,QAAQL;QAE7E,mEAAmE;QACnE,sEAAsE;QACtE,4DAA4D;QAC5D,gCAAgC;QAChC,IAAI,IAAI,CAACH,QAAQ,KAAKa,WAAW;YAC/B,OAAO,IAAI,CAACd,WAAW,CAACe,OAAO,CAACH,WAAWP;QAC7C;QAEA,gEAAgE;QAChE,wDAAwD;QACxD,8DAA8D;QAC9D,2DAA2D;QAC3D,MAAM,IAAI,CAACJ,QAAQ,CAACC,MAAM,CAACG,QAAQD,QAAQ;YACzCY,aAAaJ,UAAUK,EAAE;YACzBC,gBAAgBN,UAAUK,EAAE;QAC9B;QAEA,sEAAsE;QACtE,qEAAqE;QACrE,iEAAiE;QACjE,gEAAgE;QAChE,mEAAmE;QACnE,uDAAuD;QACvD,MAAME,SAAS,MAAM,IAAI,CAACpB,UAAU,CAACqB,eAAe,CAACR,UAAUK,EAAE;QACjE,OAAOE,UAAUP;IACnB;IAEA;;;;;;;;;GASC,GACD,MAAMS,IAAIT,SAAuB,EAAEP,MAAqB,EAAyB;QAC/E,OAAO,IAAI,CAACL,WAAW,CAACe,OAAO,CAACH,WAAWP;IAC7C;AACF;;;iEApE6BiB,wBAAW"}
@@ -0,0 +1,22 @@
1
+ import { JobExecution, JobExecutionDetails, JobExecutionFilter, JobInstance, JobInstanceFilter, JobParameters, JobRepository } from '../core/repository';
2
+ import type { JobDefinition } from '../core/ir';
3
+ import { JobRegistry } from '../registry/job-registry';
4
+ import { JobExplorer } from './job-explorer';
5
+ import { JobLauncher } from './job-launcher';
6
+ export declare class JobOperator {
7
+ private readonly explorer;
8
+ private readonly registry;
9
+ private readonly repository;
10
+ private readonly launcher;
11
+ constructor(explorer: JobExplorer, registry: JobRegistry, repository: JobRepository, launcher: JobLauncher);
12
+ listJobs(): JobDefinition[];
13
+ listJobInstances(filter?: JobInstanceFilter): Promise<JobInstance[]>;
14
+ listJobExecutions(filter?: JobExecutionFilter): Promise<JobExecution[]>;
15
+ getJobExecutionDetails(executionId: string): Promise<JobExecutionDetails>;
16
+ stop(executionId: string): Promise<JobExecutionDetails>;
17
+ abandon(executionId: string): Promise<JobExecutionDetails>;
18
+ restart(executionId: string): Promise<JobExecutionDetails>;
19
+ startNextInstance(jobId: string, params?: JobParameters): Promise<JobExecution>;
20
+ private isActive;
21
+ }
22
+ //# sourceMappingURL=job-operator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-operator.d.ts","sourceRoot":"","sources":["../../../src/execution/job-operator.ts"],"names":[],"mappings":"AAKA,OAAO,EACL,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,aAAa,EACd,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAEvD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,qBACa,WAAW;IAEpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAHR,QAAQ,EAAE,WAAW,EACrB,QAAQ,EAAE,WAAW,EACrB,UAAU,EAAE,aAAa,EACzB,QAAQ,EAAE,WAAW;IAGxC,QAAQ,IAAI,aAAa,EAAE;IAI3B,gBAAgB,CAAC,MAAM,GAAE,iBAAsB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAIxE,iBAAiB,CAAC,MAAM,GAAE,kBAAuB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAI3E,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAInE,IAAI,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAwBvD,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAyB1D,OAAO,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAiBhE,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,CAAC;IAOnF,OAAO,CAAC,QAAQ;CAOjB"}
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ Object.defineProperty(exports, "JobOperator", {
6
+ enumerable: true,
7
+ get: function() {
8
+ return JobOperator;
9
+ }
10
+ });
11
+ const _nodecrypto = require("node:crypto");
12
+ const _common = require("@nestjs/common");
13
+ const _errors = require("../core/errors");
14
+ const _repository = require("../core/repository");
15
+ const _status = require("../core/status");
16
+ const _jobregistry = require("../registry/job-registry");
17
+ const _jobexplorer = require("./job-explorer");
18
+ const _joblauncher = require("./job-launcher");
19
+ function _ts_decorate(decorators, target, key, desc) {
20
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
21
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
22
+ else for(var i = decorators.length - 1; i >= 0; i--)if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
23
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
24
+ }
25
+ function _ts_metadata(k, v) {
26
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
27
+ }
28
+ let JobOperator = class JobOperator {
29
+ explorer;
30
+ registry;
31
+ repository;
32
+ launcher;
33
+ constructor(explorer, registry, repository, launcher){
34
+ this.explorer = explorer;
35
+ this.registry = registry;
36
+ this.repository = repository;
37
+ this.launcher = launcher;
38
+ }
39
+ listJobs() {
40
+ return this.explorer.listJobs();
41
+ }
42
+ listJobInstances(filter = {}) {
43
+ return this.explorer.listJobInstances(filter);
44
+ }
45
+ listJobExecutions(filter = {}) {
46
+ return this.explorer.listJobExecutions(filter);
47
+ }
48
+ getJobExecutionDetails(executionId) {
49
+ return this.explorer.getJobExecutionDetails(executionId);
50
+ }
51
+ async stop(executionId) {
52
+ const details = await this.explorer.getJobExecutionDetails(executionId);
53
+ const status = details.jobExecution.status;
54
+ if (status === _status.JobStatus.STOPPED) {
55
+ return details;
56
+ }
57
+ if (!this.isActive(status)) {
58
+ throw new _errors.InvalidJobOperationError('stop', `Cannot stop execution in ${status} state`, {
59
+ executionId,
60
+ status
61
+ });
62
+ }
63
+ await this.repository.updateJobExecution(executionId, {
64
+ status: _status.JobStatus.STOPPED,
65
+ endTime: new Date(),
66
+ exitCode: 'STOPPED',
67
+ exitMessage: 'Stopped by JobOperator'
68
+ });
69
+ return this.explorer.getJobExecutionDetails(executionId);
70
+ }
71
+ async abandon(executionId) {
72
+ const details = await this.explorer.getJobExecutionDetails(executionId);
73
+ const status = details.jobExecution.status;
74
+ if (status === _status.JobStatus.ABANDONED) {
75
+ return details;
76
+ }
77
+ if (this.isActive(status) || status === _status.JobStatus.COMPLETED) {
78
+ throw new _errors.InvalidJobOperationError('abandon', `Cannot abandon execution in ${status} state`, {
79
+ executionId,
80
+ status
81
+ });
82
+ }
83
+ await this.repository.updateJobExecution(executionId, {
84
+ status: _status.JobStatus.ABANDONED,
85
+ endTime: details.jobExecution.endTime ?? new Date(),
86
+ exitCode: 'ABANDONED',
87
+ exitMessage: 'Abandoned by JobOperator'
88
+ });
89
+ return this.explorer.getJobExecutionDetails(executionId);
90
+ }
91
+ async restart(executionId) {
92
+ const details = await this.explorer.getJobExecutionDetails(executionId);
93
+ const status = details.jobExecution.status;
94
+ if (status !== _status.JobStatus.FAILED && status !== _status.JobStatus.STOPPED) {
95
+ throw new _errors.InvalidJobOperationError('restart', `Cannot restart execution in ${status} state`, {
96
+ executionId,
97
+ status
98
+ });
99
+ }
100
+ const jobDef = this.registry.get(details.jobInstance.jobName);
101
+ const execution = await this.launcher.run(details.jobExecution, jobDef);
102
+ return this.explorer.getJobExecutionDetails(execution.id);
103
+ }
104
+ startNextInstance(jobId, params = {}) {
105
+ return this.launcher.launch(jobId, {
106
+ ...params,
107
+ _nestBatchRunId: (0, _nodecrypto.randomUUID)()
108
+ });
109
+ }
110
+ isActive(status) {
111
+ return status === _status.JobStatus.STARTING || status === _status.JobStatus.STARTED || status === _status.JobStatus.STOPPING;
112
+ }
113
+ };
114
+ JobOperator = _ts_decorate([
115
+ (0, _common.Injectable)(),
116
+ _ts_metadata("design:type", Function),
117
+ _ts_metadata("design:paramtypes", [
118
+ typeof _jobexplorer.JobExplorer === "undefined" ? Object : _jobexplorer.JobExplorer,
119
+ typeof _jobregistry.JobRegistry === "undefined" ? Object : _jobregistry.JobRegistry,
120
+ typeof _repository.JobRepository === "undefined" ? Object : _repository.JobRepository,
121
+ typeof _joblauncher.JobLauncher === "undefined" ? Object : _joblauncher.JobLauncher
122
+ ])
123
+ ], JobOperator);
124
+
125
+ //# sourceMappingURL=job-operator.js.map