bunqueue 2.8.60 → 2.9.2

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 (427) hide show
  1. package/README.md +114 -78
  2. package/dist/application/background/dlq.js +2 -0
  3. package/dist/application/background/recovery/active.d.ts +1 -0
  4. package/dist/application/background/recovery/active.js +12 -0
  5. package/dist/application/background/recovery/index.js +3 -1
  6. package/dist/application/background/recovery/pending.js +1 -0
  7. package/dist/application/cleanupTasks.js +4 -16
  8. package/dist/application/contextFactory.js +8 -0
  9. package/dist/application/dlqManager.d.ts +10 -0
  10. package/dist/application/dlqManager.js +48 -9
  11. package/dist/application/dlqRetry.js +60 -38
  12. package/dist/application/eventsManager.d.ts +9 -2
  13. package/dist/application/eventsManager.js +106 -55
  14. package/dist/application/operations/ackHelpers.d.ts +1 -4
  15. package/dist/application/operations/ackHelpers.js +39 -14
  16. package/dist/application/operations/flowPush.js +1 -0
  17. package/dist/application/operations/flowValidation.js +4 -4
  18. package/dist/application/operations/jobManagement.d.ts +4 -0
  19. package/dist/application/operations/jobMoveOperations.js +9 -4
  20. package/dist/application/operations/pull.d.ts +7 -2
  21. package/dist/application/operations/pull.js +15 -57
  22. package/dist/application/operations/pullFinalization.d.ts +6 -0
  23. package/dist/application/operations/pullFinalization.js +69 -0
  24. package/dist/application/operations/pullStateTransition.d.ts +8 -7
  25. package/dist/application/operations/pullStateTransition.js +25 -18
  26. package/dist/application/operations/push.js +3 -0
  27. package/dist/application/operations/pushBatch.js +14 -7
  28. package/dist/application/operations/pushContext.d.ts +2 -1
  29. package/dist/application/postgres-queue-manager/batchSnapshot.d.ts +16 -0
  30. package/dist/application/postgres-queue-manager/batchSnapshot.js +17 -0
  31. package/dist/application/postgres-queue-manager/cloud.d.ts +30 -0
  32. package/dist/application/postgres-queue-manager/cloud.js +55 -0
  33. package/dist/application/postgres-queue-manager/config.d.ts +5 -0
  34. package/dist/application/postgres-queue-manager/config.js +1 -0
  35. package/dist/application/postgres-queue-manager/control.d.ts +30 -0
  36. package/dist/application/postgres-queue-manager/control.js +210 -0
  37. package/dist/application/postgres-queue-manager/deferredWrites.d.ts +13 -0
  38. package/dist/application/postgres-queue-manager/deferredWrites.js +60 -0
  39. package/dist/application/postgres-queue-manager/delivery.d.ts +20 -0
  40. package/dist/application/postgres-queue-manager/delivery.js +83 -0
  41. package/dist/application/postgres-queue-manager/groupQueries.d.ts +10 -0
  42. package/dist/application/postgres-queue-manager/groupQueries.js +40 -0
  43. package/dist/application/postgres-queue-manager/lease.d.ts +13 -0
  44. package/dist/application/postgres-queue-manager/lease.js +88 -0
  45. package/dist/application/postgres-queue-manager/lifetimeMetrics.d.ts +32 -0
  46. package/dist/application/postgres-queue-manager/lifetimeMetrics.js +53 -0
  47. package/dist/application/postgres-queue-manager/maintenance.d.ts +14 -0
  48. package/dist/application/postgres-queue-manager/maintenance.js +100 -0
  49. package/dist/application/postgres-queue-manager/operationGate.d.ts +26 -0
  50. package/dist/application/postgres-queue-manager/operationGate.js +96 -0
  51. package/dist/application/postgres-queue-manager/operations.d.ts +25 -0
  52. package/dist/application/postgres-queue-manager/operations.js +194 -0
  53. package/dist/application/postgres-queue-manager/projectionRefreshes.d.ts +43 -0
  54. package/dist/application/postgres-queue-manager/projectionRefreshes.js +170 -0
  55. package/dist/application/postgres-queue-manager/queries.d.ts +142 -0
  56. package/dist/application/postgres-queue-manager/queries.js +231 -0
  57. package/dist/application/postgres-queue-manager/relationships.d.ts +10 -0
  58. package/dist/application/postgres-queue-manager/relationships.js +45 -0
  59. package/dist/application/postgres-queue-manager/services.d.ts +31 -0
  60. package/dist/application/postgres-queue-manager/services.js +149 -0
  61. package/dist/application/postgres-queue-manager/snapshot.d.ts +51 -0
  62. package/dist/application/postgres-queue-manager/snapshot.js +236 -0
  63. package/dist/application/postgres-queue-manager/snapshotViews.d.ts +15 -0
  64. package/dist/application/postgres-queue-manager/snapshotViews.js +100 -0
  65. package/dist/application/postgres-queue-manager/startupEventBuffer.d.ts +12 -0
  66. package/dist/application/postgres-queue-manager/startupEventBuffer.js +36 -0
  67. package/dist/application/postgres-queue-manager/state.d.ts +47 -0
  68. package/dist/application/postgres-queue-manager/state.js +273 -0
  69. package/dist/application/postgres-queue-manager/terminalDelivery.d.ts +20 -0
  70. package/dist/application/postgres-queue-manager/terminalDelivery.js +100 -0
  71. package/dist/application/postgresQueueManager.d.ts +2 -0
  72. package/dist/application/postgresQueueManager.js +1 -0
  73. package/dist/application/queue-manager/control.js +1 -0
  74. package/dist/application/queue-manager/delivery.d.ts +5 -4
  75. package/dist/application/queue-manager/delivery.js +15 -8
  76. package/dist/application/queue-manager/flow-failures.js +4 -0
  77. package/dist/application/queue-manager/limits.d.ts +13 -0
  78. package/dist/application/queue-manager/limits.js +65 -0
  79. package/dist/application/queue-manager/observability.js +15 -3
  80. package/dist/application/queue-manager/queries.d.ts +7 -0
  81. package/dist/application/queue-manager/queries.js +9 -0
  82. package/dist/application/queue-manager/services.d.ts +1 -1
  83. package/dist/application/queue-manager/services.js +4 -2
  84. package/dist/application/queue-manager/state.js +17 -2
  85. package/dist/application/queueTelemetryJournal.d.ts +2 -0
  86. package/dist/application/queueTelemetryJournal.js +23 -0
  87. package/dist/application/types/ack.d.ts +3 -1
  88. package/dist/cli/commandRouter.d.ts +1 -1
  89. package/dist/cli/commands/server.js +1 -1
  90. package/dist/client/flowPush.js +6 -0
  91. package/dist/client/forwarder.d.ts +6 -4
  92. package/dist/client/forwarder.js +5 -3
  93. package/dist/client/groupId.d.ts +1 -0
  94. package/dist/client/groupId.js +1 -0
  95. package/dist/client/index.d.ts +1 -1
  96. package/dist/client/jobHelpers.js +1 -0
  97. package/dist/client/queue/dlq.d.ts +2 -0
  98. package/dist/client/queue/dlq.js +14 -0
  99. package/dist/client/queue/dlqOps.d.ts +2 -0
  100. package/dist/client/queue/dlqOps.js +4 -0
  101. package/dist/client/queue/helpers.js +2 -0
  102. package/dist/client/queue/operations/add/bulk.js +4 -4
  103. package/dist/client/queue/operations/add/payload.d.ts +1 -0
  104. package/dist/client/queue/operations/add/payload.js +7 -1
  105. package/dist/client/queue/operations/add/single.js +3 -3
  106. package/dist/client/queue/operations/groups.d.ts +21 -0
  107. package/dist/client/queue/operations/groups.js +88 -0
  108. package/dist/client/queue/runtime/configuration.d.ts +4 -0
  109. package/dist/client/queue/runtime/configuration.js +8 -0
  110. package/dist/client/queue/runtime/queries.d.ts +13 -0
  111. package/dist/client/queue/runtime/queries.js +31 -0
  112. package/dist/client/queue/runtime/state.d.ts +4 -0
  113. package/dist/client/queue/runtime/state.js +1 -0
  114. package/dist/client/types/index.d.ts +2 -2
  115. package/dist/client/types/options.d.ts +4 -0
  116. package/dist/client/types/worker.d.ts +8 -0
  117. package/dist/client/worker/runtime/execution.js +4 -8
  118. package/dist/client/worker/runtime/options.js +3 -0
  119. package/dist/client/worker/runtime/polling.d.ts +1 -0
  120. package/dist/client/worker/runtime/polling.js +9 -0
  121. package/dist/client/worker/types/options.d.ts +2 -1
  122. package/dist/client/worker/workerPull.d.ts +2 -0
  123. package/dist/client/worker/workerPull.js +6 -4
  124. package/dist/config/resolve.d.ts +14 -0
  125. package/dist/config/resolve.js +50 -5
  126. package/dist/config/types.d.ts +18 -0
  127. package/dist/domain/job/groupFifoOrder.d.ts +9 -0
  128. package/dist/domain/job/groupFifoOrder.js +26 -0
  129. package/dist/domain/queue/dlqShard.d.ts +2 -0
  130. package/dist/domain/queue/dlqShard.js +16 -0
  131. package/dist/domain/queue/groupLimiterManager.d.ts +23 -0
  132. package/dist/domain/queue/groupLimiterManager.js +107 -0
  133. package/dist/domain/queue/groupScheduler.d.ts +31 -0
  134. package/dist/domain/queue/groupScheduler.js +256 -0
  135. package/dist/domain/queue/groupSchedulerOrder.d.ts +6 -0
  136. package/dist/domain/queue/groupSchedulerOrder.js +30 -0
  137. package/dist/domain/queue/priorityQueue.d.ts +13 -23
  138. package/dist/domain/queue/priorityQueue.js +53 -42
  139. package/dist/domain/queue/shard/dlq.d.ts +1 -0
  140. package/dist/domain/queue/shard/dlq.js +3 -0
  141. package/dist/domain/queue/shard/keys.d.ts +1 -0
  142. package/dist/domain/queue/shard/keys.js +25 -2
  143. package/dist/domain/queue/shard/lifecycle.js +4 -0
  144. package/dist/domain/queue/shard/limits.d.ts +20 -1
  145. package/dist/domain/queue/shard/limits.js +56 -0
  146. package/dist/domain/queue/shard/state.d.ts +5 -0
  147. package/dist/domain/queue/shard/state.js +9 -1
  148. package/dist/domain/types/commands/core.d.ts +3 -0
  149. package/dist/domain/types/commands/dlq.d.ts +5 -0
  150. package/dist/domain/types/commands/limits.d.ts +41 -0
  151. package/dist/domain/types/commands/union.d.ts +1 -1
  152. package/dist/domain/types/cron.d.ts +5 -0
  153. package/dist/domain/types/cron.js +14 -3
  154. package/dist/domain/types/dlq.d.ts +1 -1
  155. package/dist/domain/types/dlq.js +1 -2
  156. package/dist/domain/types/group.d.ts +21 -0
  157. package/dist/domain/types/group.js +78 -0
  158. package/dist/domain/types/jobs/model.d.ts +1 -1
  159. package/dist/domain/types/priorityQueue.d.ts +1 -0
  160. package/dist/infrastructure/cloud/commandHandler.js +5 -3
  161. package/dist/infrastructure/cloud/commands/integrations.js +11 -11
  162. package/dist/infrastructure/cloud/commands/jobs.js +48 -40
  163. package/dist/infrastructure/cloud/commands/queues.js +61 -75
  164. package/dist/infrastructure/cloud/queueAdapter/local.d.ts +41 -0
  165. package/dist/infrastructure/cloud/queueAdapter/local.js +187 -0
  166. package/dist/infrastructure/cloud/queueAdapter/postgres.d.ts +42 -0
  167. package/dist/infrastructure/cloud/queueAdapter/postgres.js +188 -0
  168. package/dist/infrastructure/cloud/queueAdapter/registry.d.ts +4 -0
  169. package/dist/infrastructure/cloud/queueAdapter/registry.js +15 -0
  170. package/dist/infrastructure/cloud/queueAdapter/types.d.ts +87 -0
  171. package/dist/infrastructure/cloud/queueAdapter/types.js +1 -0
  172. package/dist/infrastructure/cloud/snapshot/analytics.d.ts +2 -0
  173. package/dist/infrastructure/cloud/snapshot/analytics.js +7 -0
  174. package/dist/infrastructure/cloud/snapshot/collector.d.ts +4 -0
  175. package/dist/infrastructure/cloud/snapshot/collector.js +39 -1
  176. package/dist/infrastructure/cloud/snapshot/config.d.ts +3 -0
  177. package/dist/infrastructure/cloud/snapshot/config.js +43 -0
  178. package/dist/infrastructure/cloud/snapshot/jobs.d.ts +3 -0
  179. package/dist/infrastructure/cloud/snapshot/jobs.js +32 -1
  180. package/dist/infrastructure/cloud/snapshotCollector.js +20 -35
  181. package/dist/infrastructure/cloud/snapshotHelpers.d.ts +3 -3
  182. package/dist/infrastructure/cloud/snapshotHelpers.js +3 -3
  183. package/dist/infrastructure/cloud/statsRefresh.js +2 -1
  184. package/dist/infrastructure/cloud/types/command.d.ts +2 -2
  185. package/dist/infrastructure/persistence/jobOptionsBlob.d.ts +1 -0
  186. package/dist/infrastructure/persistence/jobOptionsBlob.js +10 -2
  187. package/dist/infrastructure/persistence/migrations.js +11 -0
  188. package/dist/infrastructure/persistence/postgres/admission.d.ts +18 -0
  189. package/dist/infrastructure/persistence/postgres/admission.js +196 -0
  190. package/dist/infrastructure/persistence/postgres/admissionParent.d.ts +5 -0
  191. package/dist/infrastructure/persistence/postgres/admissionParent.js +35 -0
  192. package/dist/infrastructure/persistence/postgres/admissionResult.d.ts +9 -0
  193. package/dist/infrastructure/persistence/postgres/admissionResult.js +1 -0
  194. package/dist/infrastructure/persistence/postgres/admissionStore.d.ts +12 -0
  195. package/dist/infrastructure/persistence/postgres/admissionStore.js +101 -0
  196. package/dist/infrastructure/persistence/postgres/advisoryLocks.d.ts +2 -0
  197. package/dist/infrastructure/persistence/postgres/advisoryLocks.js +13 -0
  198. package/dist/infrastructure/persistence/postgres/batchAdmission.d.ts +11 -0
  199. package/dist/infrastructure/persistence/postgres/batchAdmission.js +128 -0
  200. package/dist/infrastructure/persistence/postgres/batchCompletion.d.ts +4 -0
  201. package/dist/infrastructure/persistence/postgres/batchCompletion.js +174 -0
  202. package/dist/infrastructure/persistence/postgres/batchEvents.d.ts +14 -0
  203. package/dist/infrastructure/persistence/postgres/batchEvents.js +72 -0
  204. package/dist/infrastructure/persistence/postgres/brokerSessions.d.ts +14 -0
  205. package/dist/infrastructure/persistence/postgres/brokerSessions.js +94 -0
  206. package/dist/infrastructure/persistence/postgres/claimBatch.d.ts +14 -0
  207. package/dist/infrastructure/persistence/postgres/claimBatch.js +69 -0
  208. package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +11 -0
  209. package/dist/infrastructure/persistence/postgres/claimSelection.js +140 -0
  210. package/dist/infrastructure/persistence/postgres/claims.d.ts +10 -0
  211. package/dist/infrastructure/persistence/postgres/claims.js +153 -0
  212. package/dist/infrastructure/persistence/postgres/cloudReadModel.d.ts +26 -0
  213. package/dist/infrastructure/persistence/postgres/cloudReadModel.js +123 -0
  214. package/dist/infrastructure/persistence/postgres/codec.d.ts +30 -0
  215. package/dist/infrastructure/persistence/postgres/codec.js +82 -0
  216. package/dist/infrastructure/persistence/postgres/completionEvents.d.ts +11 -0
  217. package/dist/infrastructure/persistence/postgres/completionEvents.js +21 -0
  218. package/dist/infrastructure/persistence/postgres/completionLifecycle.d.ts +11 -0
  219. package/dist/infrastructure/persistence/postgres/completionLifecycle.js +145 -0
  220. package/dist/infrastructure/persistence/postgres/completionOutcome.d.ts +4 -0
  221. package/dist/infrastructure/persistence/postgres/completionOutcome.js +112 -0
  222. package/dist/infrastructure/persistence/postgres/completionQueries.d.ts +10 -0
  223. package/dist/infrastructure/persistence/postgres/completionQueries.js +87 -0
  224. package/dist/infrastructure/persistence/postgres/connection.d.ts +3 -0
  225. package/dist/infrastructure/persistence/postgres/connection.js +15 -0
  226. package/dist/infrastructure/persistence/postgres/context.d.ts +28 -0
  227. package/dist/infrastructure/persistence/postgres/context.js +74 -0
  228. package/dist/infrastructure/persistence/postgres/control.d.ts +23 -0
  229. package/dist/infrastructure/persistence/postgres/control.js +105 -0
  230. package/dist/infrastructure/persistence/postgres/crons.d.ts +18 -0
  231. package/dist/infrastructure/persistence/postgres/crons.js +205 -0
  232. package/dist/infrastructure/persistence/postgres/deduplication.d.ts +9 -0
  233. package/dist/infrastructure/persistence/postgres/deduplication.js +47 -0
  234. package/dist/infrastructure/persistence/postgres/dependencyDestruction.d.ts +14 -0
  235. package/dist/infrastructure/persistence/postgres/dependencyDestruction.js +74 -0
  236. package/dist/infrastructure/persistence/postgres/dependencyPromotion.d.ts +29 -0
  237. package/dist/infrastructure/persistence/postgres/dependencyPromotion.js +212 -0
  238. package/dist/infrastructure/persistence/postgres/destructiveMutations.d.ts +4 -0
  239. package/dist/infrastructure/persistence/postgres/destructiveMutations.js +111 -0
  240. package/dist/infrastructure/persistence/postgres/dlqLifecycle.d.ts +13 -0
  241. package/dist/infrastructure/persistence/postgres/dlqLifecycle.js +184 -0
  242. package/dist/infrastructure/persistence/postgres/dlqMaintenance.d.ts +6 -0
  243. package/dist/infrastructure/persistence/postgres/dlqMaintenance.js +36 -0
  244. package/dist/infrastructure/persistence/postgres/dlqRetryPlan.d.ts +21 -0
  245. package/dist/infrastructure/persistence/postgres/dlqRetryPlan.js +92 -0
  246. package/dist/infrastructure/persistence/postgres/eventCatchupCursors.d.ts +32 -0
  247. package/dist/infrastructure/persistence/postgres/eventCatchupCursors.js +66 -0
  248. package/dist/infrastructure/persistence/postgres/eventCommitGc.d.ts +27 -0
  249. package/dist/infrastructure/persistence/postgres/eventCommitGc.js +62 -0
  250. package/dist/infrastructure/persistence/postgres/eventJournal.d.ts +18 -0
  251. package/dist/infrastructure/persistence/postgres/eventJournal.js +76 -0
  252. package/dist/infrastructure/persistence/postgres/eventJournalSchema.d.ts +5 -0
  253. package/dist/infrastructure/persistence/postgres/eventJournalSchema.js +267 -0
  254. package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +26 -0
  255. package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +129 -0
  256. package/dist/infrastructure/persistence/postgres/eventRetention.d.ts +18 -0
  257. package/dist/infrastructure/persistence/postgres/eventRetention.js +76 -0
  258. package/dist/infrastructure/persistence/postgres/events.d.ts +45 -0
  259. package/dist/infrastructure/persistence/postgres/events.js +276 -0
  260. package/dist/infrastructure/persistence/postgres/expiry.d.ts +3 -0
  261. package/dist/infrastructure/persistence/postgres/expiry.js +74 -0
  262. package/dist/infrastructure/persistence/postgres/flowFailures.d.ts +17 -0
  263. package/dist/infrastructure/persistence/postgres/flowFailures.js +199 -0
  264. package/dist/infrastructure/persistence/postgres/groupClaims.d.ts +15 -0
  265. package/dist/infrastructure/persistence/postgres/groupClaims.js +95 -0
  266. package/dist/infrastructure/persistence/postgres/groupSchema.d.ts +2 -0
  267. package/dist/infrastructure/persistence/postgres/groupSchema.js +155 -0
  268. package/dist/infrastructure/persistence/postgres/groupSchemaFingerprint.d.ts +3 -0
  269. package/dist/infrastructure/persistence/postgres/groupSchemaFingerprint.js +127 -0
  270. package/dist/infrastructure/persistence/postgres/groupStateRetention.d.ts +3 -0
  271. package/dist/infrastructure/persistence/postgres/groupStateRetention.js +93 -0
  272. package/dist/infrastructure/persistence/postgres/groups.d.ts +11 -0
  273. package/dist/infrastructure/persistence/postgres/groups.js +117 -0
  274. package/dist/infrastructure/persistence/postgres/jobData.d.ts +3 -0
  275. package/dist/infrastructure/persistence/postgres/jobData.js +32 -0
  276. package/dist/infrastructure/persistence/postgres/leaseRelease.d.ts +9 -0
  277. package/dist/infrastructure/persistence/postgres/leaseRelease.js +120 -0
  278. package/dist/infrastructure/persistence/postgres/leaseRenewal.d.ts +4 -0
  279. package/dist/infrastructure/persistence/postgres/leaseRenewal.js +35 -0
  280. package/dist/infrastructure/persistence/postgres/lifetimeMetrics.d.ts +15 -0
  281. package/dist/infrastructure/persistence/postgres/lifetimeMetrics.js +46 -0
  282. package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.d.ts +4 -0
  283. package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.js +13 -0
  284. package/dist/infrastructure/persistence/postgres/logs.d.ts +6 -0
  285. package/dist/infrastructure/persistence/postgres/logs.js +70 -0
  286. package/dist/infrastructure/persistence/postgres/maintenance.d.ts +6 -0
  287. package/dist/infrastructure/persistence/postgres/maintenance.js +138 -0
  288. package/dist/infrastructure/persistence/postgres/maintenanceFlights.d.ts +14 -0
  289. package/dist/infrastructure/persistence/postgres/maintenanceFlights.js +66 -0
  290. package/dist/infrastructure/persistence/postgres/metricWrites.d.ts +9 -0
  291. package/dist/infrastructure/persistence/postgres/metricWrites.js +94 -0
  292. package/dist/infrastructure/persistence/postgres/mutations.d.ts +9 -0
  293. package/dist/infrastructure/persistence/postgres/mutations.js +171 -0
  294. package/dist/infrastructure/persistence/postgres/outcomes.d.ts +4 -0
  295. package/dist/infrastructure/persistence/postgres/outcomes.js +194 -0
  296. package/dist/infrastructure/persistence/postgres/policies.d.ts +11 -0
  297. package/dist/infrastructure/persistence/postgres/policies.js +18 -0
  298. package/dist/infrastructure/persistence/postgres/postCommitMaintenance.d.ts +17 -0
  299. package/dist/infrastructure/persistence/postgres/postCommitMaintenance.js +117 -0
  300. package/dist/infrastructure/persistence/postgres/promotion.d.ts +3 -0
  301. package/dist/infrastructure/persistence/postgres/promotion.js +43 -0
  302. package/dist/infrastructure/persistence/postgres/queries.d.ts +22 -0
  303. package/dist/infrastructure/persistence/postgres/queries.js +152 -0
  304. package/dist/infrastructure/persistence/postgres/queueDestruction.d.ts +3 -0
  305. package/dist/infrastructure/persistence/postgres/queueDestruction.js +158 -0
  306. package/dist/infrastructure/persistence/postgres/queueLifecycle.d.ts +10 -0
  307. package/dist/infrastructure/persistence/postgres/queueLifecycle.js +60 -0
  308. package/dist/infrastructure/persistence/postgres/rateLimit.d.ts +6 -0
  309. package/dist/infrastructure/persistence/postgres/rateLimit.js +10 -0
  310. package/dist/infrastructure/persistence/postgres/readModels.d.ts +32 -0
  311. package/dist/infrastructure/persistence/postgres/readModels.js +72 -0
  312. package/dist/infrastructure/persistence/postgres/recovery.d.ts +3 -0
  313. package/dist/infrastructure/persistence/postgres/recovery.js +178 -0
  314. package/dist/infrastructure/persistence/postgres/relationships.d.ts +9 -0
  315. package/dist/infrastructure/persistence/postgres/relationships.js +201 -0
  316. package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.d.ts +4 -0
  317. package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.js +241 -0
  318. package/dist/infrastructure/persistence/postgres/repeatMutations.d.ts +5 -0
  319. package/dist/infrastructure/persistence/postgres/repeatMutations.js +37 -0
  320. package/dist/infrastructure/persistence/postgres/runtime.d.ts +45 -0
  321. package/dist/infrastructure/persistence/postgres/runtime.js +238 -0
  322. package/dist/infrastructure/persistence/postgres/runtimeConfig.d.ts +21 -0
  323. package/dist/infrastructure/persistence/postgres/runtimeConfig.js +39 -0
  324. package/dist/infrastructure/persistence/postgres/schema.d.ts +4 -0
  325. package/dist/infrastructure/persistence/postgres/schema.js +261 -0
  326. package/dist/infrastructure/persistence/postgres/schemaInitialization.d.ts +3 -0
  327. package/dist/infrastructure/persistence/postgres/schemaInitialization.js +226 -0
  328. package/dist/infrastructure/persistence/postgres/serialAdmission.d.ts +6 -0
  329. package/dist/infrastructure/persistence/postgres/serialAdmission.js +96 -0
  330. package/dist/infrastructure/persistence/postgres/snapshotBudget.d.ts +3 -0
  331. package/dist/infrastructure/persistence/postgres/snapshotBudget.js +83 -0
  332. package/dist/infrastructure/persistence/postgres/storageHealth.d.ts +10 -0
  333. package/dist/infrastructure/persistence/postgres/storageHealth.js +29 -0
  334. package/dist/infrastructure/persistence/postgres/store.d.ts +100 -0
  335. package/dist/infrastructure/persistence/postgres/store.js +180 -0
  336. package/dist/infrastructure/persistence/postgres/telemetry.d.ts +8 -0
  337. package/dist/infrastructure/persistence/postgres/telemetry.js +100 -0
  338. package/dist/infrastructure/persistence/postgres/terminal.d.ts +8 -0
  339. package/dist/infrastructure/persistence/postgres/terminal.js +137 -0
  340. package/dist/infrastructure/persistence/postgres/transactionRetry.d.ts +6 -0
  341. package/dist/infrastructure/persistence/postgres/transactionRetry.js +42 -0
  342. package/dist/infrastructure/persistence/postgres/types.d.ts +176 -0
  343. package/dist/infrastructure/persistence/postgres/types.js +1 -0
  344. package/dist/infrastructure/persistence/postgres/workers.d.ts +15 -0
  345. package/dist/infrastructure/persistence/postgres/workers.js +126 -0
  346. package/dist/infrastructure/persistence/postgres.d.ts +2 -0
  347. package/dist/infrastructure/persistence/postgres.js +1 -0
  348. package/dist/infrastructure/persistence/schema.d.ts +2 -2
  349. package/dist/infrastructure/persistence/schema.js +12 -1
  350. package/dist/infrastructure/persistence/sqlite/control.d.ts +14 -0
  351. package/dist/infrastructure/persistence/sqlite/control.js +69 -0
  352. package/dist/infrastructure/persistence/sqlite/jobs.d.ts +12 -0
  353. package/dist/infrastructure/persistence/sqlite/jobs.js +38 -0
  354. package/dist/infrastructure/persistence/sqlite/telemetry.d.ts +2 -1
  355. package/dist/infrastructure/persistence/sqlite/telemetry.js +5 -64
  356. package/dist/infrastructure/persistence/sqlite/telemetryWrites.d.ts +4 -0
  357. package/dist/infrastructure/persistence/sqlite/telemetryWrites.js +123 -0
  358. package/dist/infrastructure/persistence/sqliteSerializer.js +2 -0
  359. package/dist/infrastructure/scheduler/cron/persisted.d.ts +5 -0
  360. package/dist/infrastructure/scheduler/cron/persisted.js +27 -0
  361. package/dist/infrastructure/scheduler/cron/runtime.js +5 -10
  362. package/dist/infrastructure/scheduler/cron/validation.d.ts +3 -0
  363. package/dist/infrastructure/scheduler/cron/validation.js +11 -0
  364. package/dist/infrastructure/scheduler/cronParser.d.ts +1 -1
  365. package/dist/infrastructure/scheduler/cronParser.js +144 -11
  366. package/dist/infrastructure/server/bootstrap.d.ts +2 -3
  367. package/dist/infrastructure/server/bootstrap.js +33 -59
  368. package/dist/infrastructure/server/errors.d.ts +4 -0
  369. package/dist/infrastructure/server/errors.js +54 -0
  370. package/dist/infrastructure/server/handler-routes/control.d.ts +5 -5
  371. package/dist/infrastructure/server/handler-routes/control.js +16 -1
  372. package/dist/infrastructure/server/handler-routes/monitoring.d.ts +2 -2
  373. package/dist/infrastructure/server/handler.js +9 -11
  374. package/dist/infrastructure/server/handlers/advanced/dependencies.js +7 -6
  375. package/dist/infrastructure/server/handlers/advanced/jobs.js +19 -6
  376. package/dist/infrastructure/server/handlers/advanced/queue.d.ts +9 -9
  377. package/dist/infrastructure/server/handlers/advanced/queue.js +91 -27
  378. package/dist/infrastructure/server/handlers/core.d.ts +0 -5
  379. package/dist/infrastructure/server/handlers/core.js +47 -49
  380. package/dist/infrastructure/server/handlers/cron.d.ts +4 -4
  381. package/dist/infrastructure/server/handlers/cron.js +60 -59
  382. package/dist/infrastructure/server/handlers/dashboard.d.ts +1 -1
  383. package/dist/infrastructure/server/handlers/dashboard.js +21 -8
  384. package/dist/infrastructure/server/handlers/dlq.d.ts +6 -3
  385. package/dist/infrastructure/server/handlers/dlq.js +35 -9
  386. package/dist/infrastructure/server/handlers/flow.js +2 -1
  387. package/dist/infrastructure/server/handlers/groups.d.ts +11 -0
  388. package/dist/infrastructure/server/handlers/groups.js +55 -0
  389. package/dist/infrastructure/server/handlers/management.d.ts +5 -5
  390. package/dist/infrastructure/server/handlers/management.js +36 -9
  391. package/dist/infrastructure/server/handlers/monitoring/health.d.ts +5 -5
  392. package/dist/infrastructure/server/handlers/monitoring/health.js +45 -16
  393. package/dist/infrastructure/server/handlers/monitoring/operations.d.ts +1 -1
  394. package/dist/infrastructure/server/handlers/monitoring/operations.js +8 -1
  395. package/dist/infrastructure/server/handlers/monitoring/workers.d.ts +3 -3
  396. package/dist/infrastructure/server/handlers/monitoring/workers.js +31 -7
  397. package/dist/infrastructure/server/handlers/pushBatchValidation.d.ts +3 -1
  398. package/dist/infrastructure/server/handlers/pushBatchValidation.js +56 -8
  399. package/dist/infrastructure/server/handlers/query.d.ts +1 -1
  400. package/dist/infrastructure/server/handlers/query.js +5 -4
  401. package/dist/infrastructure/server/http.js +2 -2
  402. package/dist/infrastructure/server/httpDashboardEndpoints.d.ts +1 -1
  403. package/dist/infrastructure/server/httpDashboardEndpoints.js +19 -6
  404. package/dist/infrastructure/server/httpEndpoints.js +18 -7
  405. package/dist/infrastructure/server/httpRouteQueues.js +11 -1
  406. package/dist/infrastructure/server/protocol/validation.d.ts +1 -0
  407. package/dist/infrastructure/server/protocol/validation.js +1 -0
  408. package/dist/infrastructure/server/protocol.d.ts +1 -1
  409. package/dist/infrastructure/server/protocol.js +1 -1
  410. package/dist/infrastructure/server/shutdownCoordinator.d.ts +24 -0
  411. package/dist/infrastructure/server/shutdownCoordinator.js +106 -0
  412. package/dist/infrastructure/server/sseHandler.js +8 -3
  413. package/dist/infrastructure/server/storageAdapter.d.ts +29 -0
  414. package/dist/infrastructure/server/storageAdapter.js +61 -0
  415. package/dist/infrastructure/server/storageManager.d.ts +12 -0
  416. package/dist/infrastructure/server/storageManager.js +102 -0
  417. package/dist/infrastructure/server/tcp.js +2 -3
  418. package/dist/infrastructure/server/ws/snapshots.d.ts +1 -1
  419. package/dist/infrastructure/server/ws/snapshots.js +19 -4
  420. package/dist/infrastructure/server/wsHandler.js +10 -5
  421. package/dist/main.js +1 -1
  422. package/dist/mcp/backend/embedded/services.js +2 -1
  423. package/dist/mcp/index.d.ts +2 -2
  424. package/dist/mcp/index.js +2 -2
  425. package/dist/shared/storageHealth.d.ts +9 -0
  426. package/dist/shared/storageHealth.js +12 -0
  427. package/package.json +75 -65
@@ -3,33 +3,63 @@ import { MAX_TIMELINE_ENTRIES } from '../domain/types/job';
3
3
  import { retainDlqRetryState, scheduleNextRetry, setDlqRetryState } from '../domain/types/dlq';
4
4
  import { shardIndex } from '../shared/hash';
5
5
  function prepareRetry(job, now) {
6
- job.attempts = 0;
7
- job.runAt = now;
8
- job.startedAt = null;
9
- job.stallCount = 0;
10
- job.lastHeartbeat = now;
11
- if (job.timeline.length < MAX_TIMELINE_ENTRIES) {
12
- job.timeline.push({ state: 'waiting', timestamp: now });
13
- }
6
+ const timeline = [...job.timeline];
7
+ if (timeline.length < MAX_TIMELINE_ENTRIES)
8
+ timeline.push({ state: 'waiting', timestamp: now });
9
+ return {
10
+ ...job,
11
+ attempts: 0,
12
+ lastHeartbeat: now,
13
+ runAt: now,
14
+ stallCount: 0,
15
+ startedAt: null,
16
+ timeline,
17
+ };
18
+ }
19
+ function canRetry(queue, job, ctx) {
20
+ const idx = shardIndex(queue);
21
+ const shard = ctx.shards[idx];
22
+ const location = ctx.jobIndex.get(job.id);
23
+ if (location?.type !== 'dlq' || location.queueName !== queue)
24
+ return false;
25
+ const customOwner = job.customId ? ctx.customIdMap.get(job.customId) : undefined;
26
+ if (customOwner && customOwner !== job.id)
27
+ return false;
28
+ const keyOwner = job.uniqueKey ? shard.getUniqueKeyEntry(queue, job.uniqueKey) : null;
29
+ return keyOwner === null || keyOwner.jobId === job.id;
14
30
  }
15
- function enqueueRetry(queue, job, now, ctx) {
31
+ function publishRetry(queue, job, ctx) {
16
32
  const idx = shardIndex(queue);
17
33
  const shard = ctx.shards[idx];
18
- prepareRetry(job, now);
19
34
  shard.getQueue(queue).push(job);
20
- shard.incrementQueued(job.id, job.runAt > now, job.createdAt, queue, job.runAt);
35
+ shard.incrementQueued(job.id, false, job.createdAt, queue, job.runAt);
21
36
  ctx.jobIndex.set(job.id, { type: 'queue', shardIdx: idx, queueName: queue });
37
+ if (job.customId)
38
+ ctx.customIdMap.set(job.customId, job.id);
39
+ if (job.uniqueKey) {
40
+ shard.registerUniqueKeyWithTtl(queue, job.uniqueKey, job.id, job.deduplicationTtl ?? undefined);
41
+ }
42
+ }
43
+ function retryEntry(queue, entry, ctx, now, prepareState) {
44
+ if (!canRetry(queue, entry.job, ctx))
45
+ return null;
46
+ const job = prepareRetry(entry.job, now);
47
+ ctx.shards[shardIndex(queue)].assignGroupFifoOrder(job);
48
+ prepareState(job);
22
49
  ctx.storage?.requeueDlqJob(job);
50
+ const removed = ctx.shards[shardIndex(queue)].removeFromDlq(queue, entry.job.id);
51
+ if (!removed)
52
+ throw new Error('DLQ entry disappeared after its retry committed');
53
+ publishRetry(queue, job, ctx);
54
+ return job;
23
55
  }
24
56
  /** Retry a single job from DLQ and reset the automatic retry generation. */
25
57
  export function retryDlqJob(queue, jobId, ctx) {
26
58
  const shard = ctx.shards[shardIndex(queue)];
27
- const entry = shard.removeFromDlq(queue, jobId);
59
+ const entry = shard.getDlqEntries(queue).find((candidate) => candidate.job.id === jobId);
28
60
  if (!entry)
29
61
  return null;
30
- setDlqRetryState(entry.job, null);
31
- enqueueRetry(queue, entry.job, Date.now(), ctx);
32
- return entry.job;
62
+ return retryEntry(queue, entry, ctx, Date.now(), (job) => setDlqRetryState(job, null));
33
63
  }
34
64
  /** Retry jobs from DLQ, optionally bounded to the oldest `limit` entries. */
35
65
  export function retryDlqJobs(queue, ctx, jobId, limit) {
@@ -49,29 +79,21 @@ export function retryDlqJobs(queue, ctx, jobId, limit) {
49
79
  }
50
80
  return retried;
51
81
  }
52
- const entries = [...shard.getDlqEntries(queue)];
53
- shard.clearDlq(queue);
54
- ctx.storage?.clearDlqQueue(queue);
55
- const now = Date.now();
56
- for (const entry of entries) {
57
- setDlqRetryState(entry.job, null);
58
- enqueueRetry(queue, entry.job, now, ctx);
59
- }
60
- return entries.length;
82
+ const ids = shard.getDlqEntries(queue).map((entry) => entry.job.id);
83
+ let retried = 0;
84
+ for (const id of ids)
85
+ if (retryDlqJob(queue, id, ctx))
86
+ retried++;
87
+ return retried;
61
88
  }
62
89
  /** Retry all DLQ entries selected by a metadata filter. */
63
90
  export function retryDlqByFilter(queue, ctx, filter) {
64
91
  const shard = ctx.shards[shardIndex(queue)];
65
92
  const entries = [...shard.getDlqFiltered(queue, filter)];
66
- const now = Date.now();
67
93
  let retried = 0;
68
94
  for (const entry of entries) {
69
- const removed = shard.removeFromDlq(queue, entry.job.id);
70
- if (!removed)
71
- continue;
72
- setDlqRetryState(removed.job, null);
73
- enqueueRetry(queue, removed.job, now, ctx);
74
- retried++;
95
+ if (retryDlqJob(queue, entry.job.id, ctx))
96
+ retried++;
75
97
  }
76
98
  return retried;
77
99
  }
@@ -85,13 +107,13 @@ export function processAutoRetry(queue, ctx) {
85
107
  const entries = [...shard.getAutoRetryEntries(queue, now)];
86
108
  let retried = 0;
87
109
  for (const entry of entries) {
88
- const removed = shard.removeFromDlq(queue, entry.job.id);
89
- if (!removed)
90
- continue;
91
- scheduleNextRetry(removed, config);
92
- retainDlqRetryState(removed.job, removed);
93
- enqueueRetry(queue, removed.job, now, ctx);
94
- retried++;
110
+ const scheduled = { ...entry, attempts: [...entry.attempts] };
111
+ scheduleNextRetry(scheduled, config);
112
+ const job = retryEntry(queue, entry, ctx, now, (candidate) => {
113
+ retainDlqRetryState(candidate, scheduled);
114
+ });
115
+ if (job)
116
+ retried++;
95
117
  }
96
118
  return retried;
97
119
  }
@@ -7,11 +7,14 @@ import { EventType, type JobEvent } from '../domain/types/queue';
7
7
  import type { WebhookManager } from './webhookManager';
8
8
  /** Event subscriber callback */
9
9
  export type EventSubscriber = (event: JobEvent) => void;
10
+ export type EventBatchSubscriber = (events: readonly JobEvent[]) => void;
10
11
  /** Events manager class */
11
12
  export declare class EventsManager {
12
13
  private readonly webhookManager;
13
14
  /** Use Set for O(1) subscribe/unsubscribe instead of indexOf+splice */
14
15
  private readonly subscribers;
16
+ /** Optional batch path for internal subscribers such as durable telemetry. */
17
+ private readonly batchSubscribers;
15
18
  /** Waiters for specific job completions - for efficient WaitJob implementation */
16
19
  private readonly completionWaiters;
17
20
  constructor(webhookManager: WebhookManager);
@@ -20,14 +23,14 @@ export declare class EventsManager {
20
23
  /** Number of jobs with active completion waiters */
21
24
  get completionWaiterCount(): number;
22
25
  /** Subscribe to job events - O(1) add and remove */
23
- subscribe(callback: EventSubscriber): () => void;
26
+ subscribe(callback: EventSubscriber, batchCallback?: EventBatchSubscriber): () => void;
24
27
  /** Clear all subscribers (for shutdown) */
25
28
  clear(): void;
26
29
  /**
27
30
  * Wait for a specific job to complete - event-driven, no polling
28
31
  * Returns true if job completed, false if timeout
29
32
  */
30
- waitForJobCompletion(jobId: JobId, timeoutMs: number): Promise<boolean>;
33
+ waitForJobCompletion(jobId: JobId, timeoutMs: number, signal?: AbortSignal): Promise<boolean>;
31
34
  /** Check if broadcast has any listeners - for batch optimizations */
32
35
  needsBroadcast(): boolean;
33
36
  /** Broadcast event to all subscribers - optimized to skip work when no listeners */
@@ -38,6 +41,10 @@ export declare class EventsManager {
38
41
  timestamp: number;
39
42
  error?: string;
40
43
  }): void;
44
+ /** Broadcast an ordered batch while allowing internal subscribers to persist once. */
45
+ broadcastBatch(events: readonly JobEvent[]): void;
46
+ private notifyCompletionWaiters;
47
+ private triggerWebhook;
41
48
  /** Map internal event type to webhook event */
42
49
  private mapEventToWebhook;
43
50
  }
@@ -8,6 +8,8 @@ export class EventsManager {
8
8
  webhookManager;
9
9
  /** Use Set for O(1) subscribe/unsubscribe instead of indexOf+splice */
10
10
  subscribers = new Set();
11
+ /** Optional batch path for internal subscribers such as durable telemetry. */
12
+ batchSubscribers = new Map();
11
13
  /** Waiters for specific job completions - for efficient WaitJob implementation */
12
14
  completionWaiters = new Map();
13
15
  constructor(webhookManager) {
@@ -22,21 +24,24 @@ export class EventsManager {
22
24
  return this.completionWaiters.size;
23
25
  }
24
26
  /** Subscribe to job events - O(1) add and remove */
25
- subscribe(callback) {
27
+ subscribe(callback, batchCallback) {
26
28
  this.subscribers.add(callback);
29
+ if (batchCallback)
30
+ this.batchSubscribers.set(callback, batchCallback);
27
31
  return () => {
28
32
  this.subscribers.delete(callback); // O(1) instead of O(n)
33
+ this.batchSubscribers.delete(callback);
29
34
  };
30
35
  }
31
36
  /** Clear all subscribers (for shutdown) */
32
37
  clear() {
33
38
  this.subscribers.clear();
39
+ this.batchSubscribers.clear();
34
40
  // Clear all waiters
35
41
  for (const waiters of this.completionWaiters.values()) {
36
42
  for (const waiter of waiters) {
37
- if (!waiter.cancelled) {
43
+ if (!waiter.cancelled)
38
44
  waiter.resolve();
39
- }
40
45
  }
41
46
  }
42
47
  this.completionWaiters.clear();
@@ -45,40 +50,45 @@ export class EventsManager {
45
50
  * Wait for a specific job to complete - event-driven, no polling
46
51
  * Returns true if job completed, false if timeout
47
52
  */
48
- waitForJobCompletion(jobId, timeoutMs) {
53
+ waitForJobCompletion(jobId, timeoutMs, signal) {
49
54
  const jobKey = String(jobId);
55
+ if (signal?.aborted)
56
+ return Promise.resolve(false);
50
57
  return new Promise((resolve) => {
58
+ let settled = false;
59
+ const cleanup = () => {
60
+ clearTimeout(timer);
61
+ signal?.removeEventListener('abort', onAbort);
62
+ const waiters = this.completionWaiters.get(jobKey);
63
+ waiters?.delete(waiter);
64
+ if (waiters?.size === 0)
65
+ this.completionWaiters.delete(jobKey);
66
+ };
67
+ const finish = (completed) => {
68
+ if (settled)
69
+ return;
70
+ settled = true;
71
+ waiter.cancelled = !completed;
72
+ cleanup();
73
+ resolve(completed);
74
+ };
75
+ const onAbort = () => finish(false);
51
76
  const waiter = {
52
- resolve: () => {
53
- clearTimeout(timer);
54
- resolve(true);
55
- },
77
+ resolve: () => finish(true),
78
+ cancel: () => finish(false),
56
79
  cancelled: false,
57
80
  };
58
- const timer = setTimeout(() => {
59
- // Timeout - mark as cancelled and remove from map to prevent memory leak
60
- waiter.cancelled = true;
61
- // Remove the waiter from the array
62
- const waiters = this.completionWaiters.get(jobKey);
63
- if (waiters) {
64
- const index = waiters.indexOf(waiter);
65
- if (index !== -1) {
66
- waiters.splice(index, 1);
67
- }
68
- // Clean up empty arrays to free memory
69
- if (waiters.length === 0) {
70
- this.completionWaiters.delete(jobKey);
71
- }
72
- }
73
- resolve(false);
74
- }, timeoutMs);
75
81
  // Add to waiters
76
82
  let waiters = this.completionWaiters.get(jobKey);
77
83
  if (!waiters) {
78
- waiters = [];
84
+ waiters = new Set();
79
85
  this.completionWaiters.set(jobKey, waiters);
80
86
  }
81
- waiters.push(waiter);
87
+ waiters.add(waiter);
88
+ const timer = setTimeout(() => finish(false), timeoutMs);
89
+ signal?.addEventListener('abort', onAbort, { once: true });
90
+ if (signal?.aborted)
91
+ onAbort();
82
92
  });
83
93
  }
84
94
  /** Check if broadcast has any listeners - for batch optimizations */
@@ -108,40 +118,81 @@ export class EventsManager {
108
118
  }
109
119
  }
110
120
  }
111
- // Notify completion waiters for WaitJob - O(1) lookup
112
- if (hasWaiters) {
113
- const jobKey = String(event.jobId);
114
- const waiters = this.completionWaiters.get(jobKey);
115
- if (waiters) {
116
- this.completionWaiters.delete(jobKey);
117
- // Only notify non-cancelled waiters
118
- for (const waiter of waiters) {
119
- if (!waiter.cancelled) {
120
- waiter.resolve();
121
- }
121
+ if (hasWaiters)
122
+ this.notifyCompletionWaiters(event);
123
+ if (hasWebhooks)
124
+ this.triggerWebhook(event);
125
+ }
126
+ /** Broadcast an ordered batch while allowing internal subscribers to persist once. */
127
+ broadcastBatch(events) {
128
+ if (events.length === 0)
129
+ return;
130
+ const hasSubscribers = this.subscribers.size > 0;
131
+ const hasWebhooks = this.webhookManager.hasEnabledWebhooks();
132
+ const hasWaiters = this.completionWaiters.size > 0;
133
+ if (!hasSubscribers && !hasWebhooks && !hasWaiters)
134
+ return;
135
+ if (hasSubscribers) {
136
+ for (const [subscriber, batchSubscriber] of this.batchSubscribers) {
137
+ if (!this.subscribers.has(subscriber))
138
+ continue;
139
+ try {
140
+ batchSubscriber(events);
141
+ }
142
+ catch {
143
+ // Ignore subscriber errors.
122
144
  }
123
145
  }
124
146
  }
125
- // Trigger webhooks - only if there are enabled webhooks
126
- if (hasWebhooks) {
127
- const webhookEvent = this.mapEventToWebhook(event.eventType);
128
- if (webhookEvent) {
129
- this.webhookManager
130
- .trigger(webhookEvent, String(event.jobId), event.queue, {
131
- data: event.data,
132
- error: event.error,
133
- })
134
- .catch((err) => {
135
- webhookLog.error('Webhook trigger failed', {
136
- event: webhookEvent,
137
- jobId: String(event.jobId),
138
- queue: event.queue,
139
- error: String(err),
140
- });
141
- });
147
+ for (const event of events) {
148
+ if (hasSubscribers) {
149
+ for (const subscriber of this.subscribers) {
150
+ if (this.batchSubscribers.has(subscriber))
151
+ continue;
152
+ try {
153
+ subscriber(event);
154
+ }
155
+ catch {
156
+ // Ignore subscriber errors and continue with the ordered batch.
157
+ }
158
+ }
142
159
  }
160
+ if (hasWaiters && event.eventType === "completed" /* EventType.Completed */) {
161
+ this.notifyCompletionWaiters(event);
162
+ }
163
+ if (hasWebhooks)
164
+ this.triggerWebhook(event);
165
+ }
166
+ }
167
+ notifyCompletionWaiters(event) {
168
+ const jobKey = String(event.jobId);
169
+ const waiters = this.completionWaiters.get(jobKey);
170
+ if (!waiters)
171
+ return;
172
+ this.completionWaiters.delete(jobKey);
173
+ for (const waiter of waiters) {
174
+ if (!waiter.cancelled)
175
+ waiter.resolve();
143
176
  }
144
177
  }
178
+ triggerWebhook(event) {
179
+ const webhookEvent = this.mapEventToWebhook(event.eventType);
180
+ if (!webhookEvent)
181
+ return;
182
+ this.webhookManager
183
+ .trigger(webhookEvent, String(event.jobId), event.queue, {
184
+ data: event.data,
185
+ error: event.error,
186
+ })
187
+ .catch((err) => {
188
+ webhookLog.error('Webhook trigger failed', {
189
+ event: webhookEvent,
190
+ jobId: String(event.jobId),
191
+ queue: event.queue,
192
+ error: String(err),
193
+ });
194
+ });
195
+ }
145
196
  /** Map internal event type to webhook event */
146
197
  mapEventToWebhook(eventType) {
147
198
  switch (eventType) {
@@ -2,10 +2,7 @@
2
2
  import type { Job, JobId } from '../../domain/types/job';
3
3
  import type { BatchContext, ExtractedJob, FinalizeContext } from '../types/ack';
4
4
  export type { BatchContext, ExtractedJob, FinalizeContext } from '../types/ack';
5
- /**
6
- * Group job IDs by processing shard
7
- * Returns Map<shardIndex, jobIds[]>
8
- */
5
+ /** Group job IDs by processing shard. */
9
6
  export declare function groupByProcShard(jobIds: JobId[]): Map<number, JobId[]>;
10
7
  /**
11
8
  * Group items by processing shard (with results)
@@ -4,10 +4,30 @@ import { withWriteLock } from '../../shared/lock';
4
4
  import { shardIndex, processingShardIndex } from '../../shared/hash';
5
5
  import { throughputTracker } from '../throughputTracker';
6
6
  import { commitRemovedCompletion } from '../dependencyCompletions';
7
- /**
8
- * Group job IDs by processing shard
9
- * Returns Map<shardIndex, jobIds[]>
10
- */
7
+ /** Batch only when no per-job durable result/removal ordering must be preserved. */
8
+ function persistCompletedBatch(extractedJobs, ctx, includeResults, now) {
9
+ const storage = ctx.storage;
10
+ if (!storage || extractedJobs.length === 0)
11
+ return false;
12
+ if (extractedJobs.some(({ job, removeOnComplete }) => job.removeOnComplete || removeOnComplete === true) ||
13
+ (includeResults && extractedJobs.some(({ result }) => result !== undefined))) {
14
+ return false;
15
+ }
16
+ try {
17
+ storage.markCompletedBatch(extractedJobs.map(({ id: jobId, job }) => ({
18
+ jobId,
19
+ completedAt: now,
20
+ timeline: job.timeline.length < MAX_TIMELINE_ENTRIES
21
+ ? [...job.timeline, { state: 'completed', timestamp: now }]
22
+ : job.timeline,
23
+ })));
24
+ return true;
25
+ }
26
+ catch {
27
+ return false;
28
+ }
29
+ }
30
+ /** Group job IDs by processing shard. */
11
31
  export function groupByProcShard(jobIds) {
12
32
  const byProcShard = new Map();
13
33
  for (const jobId of jobIds) {
@@ -119,6 +139,7 @@ export function finalizeBatchAck(extractedJobs, ctx, includeResults) {
119
139
  const jobCount = extractedJobs.length;
120
140
  const needsBroadcast = ctx.needsBroadcast?.() ?? true;
121
141
  const hasPendingDeps = ctx.hasPendingDeps?.() ?? true;
142
+ const completionBatchPersisted = persistCompletedBatch(extractedJobs, ctx, includeResults, now);
122
143
  // Batch counter update
123
144
  ctx.totalCompleted.value += BigInt(jobCount);
124
145
  // Per-queue completed counter update
@@ -160,8 +181,9 @@ export function finalizeBatchAck(extractedJobs, ctx, includeResults) {
160
181
  // 2. Update job index and store job data for completed listing
161
182
  ctx.jobIndex.set(jobId, { type: 'completed', queueName: job.queue });
162
183
  ctx.completedJobsData.set(jobId, job);
163
- if (hasStorage)
184
+ if (hasStorage && !completionBatchPersisted) {
164
185
  storage.markCompleted(jobId, now, job.timeline);
186
+ }
165
187
  // 3. Mark as completed LAST - this is the signal other threads wait for
166
188
  ctx.completedJobs.add(jobId);
167
189
  }
@@ -180,15 +202,18 @@ export function finalizeBatchAck(extractedJobs, ctx, includeResults) {
180
202
  }
181
203
  // Broadcast events
182
204
  if (needsBroadcast) {
183
- for (let i = 0; i < jobCount; i++) {
184
- const { id: jobId, job, result } = extractedJobs[i];
185
- ctx.broadcast({
186
- eventType: 'completed',
187
- queue: job.queue,
188
- jobId,
189
- timestamp: now,
190
- data: includeResults ? result : undefined,
191
- });
205
+ const events = extractedJobs.map(({ id: jobId, job, result }) => ({
206
+ eventType: 'completed',
207
+ queue: job.queue,
208
+ jobId,
209
+ timestamp: now,
210
+ data: includeResults ? result : undefined,
211
+ }));
212
+ if (ctx.broadcastBatch)
213
+ ctx.broadcastBatch(events);
214
+ else {
215
+ for (const event of events)
216
+ ctx.broadcast(event);
192
217
  }
193
218
  }
194
219
  // Notify completions
@@ -29,6 +29,7 @@ function assertIdsAvailable(batch, ctx) {
29
29
  function prepareJobs(batch, ctx, now) {
30
30
  return batch.jobs.map((planned) => {
31
31
  const job = createJob(planned.id, planned.queue, planned.input, now);
32
+ ctx.shards[shardIndex(planned.queue)].assignGroupFifoOrder(job);
32
33
  job.timeline.push({ state: initialJobState(job, ctx, now), timestamp: now });
33
34
  return job;
34
35
  });
@@ -1,3 +1,4 @@
1
+ import { validateGroupId } from '../../domain/types/group';
1
2
  import { normalizeJobPayload } from '../../domain/types/job';
2
3
  import { validateFlowTopology } from './flowTopologyValidation';
3
4
  const MAX_FLOW_JOBS = 10_000;
@@ -52,10 +53,9 @@ function validateOptions(input) {
52
53
  throw new Error(`${name} must be a boolean`);
53
54
  }
54
55
  }
55
- if (input.groupId !== undefined &&
56
- (typeof input.groupId !== 'string' || input.groupId.length > 256)) {
57
- throw new Error('groupId must be a string of at most 256 characters');
58
- }
56
+ const groupError = validateGroupId(input.groupId);
57
+ if (groupError)
58
+ throw new Error(groupError);
59
59
  if (input.tags !== undefined &&
60
60
  (!Array.isArray(input.tags) ||
61
61
  input.tags.some((tag) => typeof tag !== 'string' || tag.length > 256))) {
@@ -26,6 +26,10 @@ export interface JobManagementContext {
26
26
  eventsManager: EventsManager;
27
27
  repeatChain?: Map<JobId, JobId>;
28
28
  dependencyResults: DependencyResultTracker;
29
+ customIdMap: {
30
+ get(id: string): JobId | undefined;
31
+ delete(id: string): boolean;
32
+ };
29
33
  depCompletions?: DependencyCompletionTracker;
30
34
  maxDependencyCompletions: number;
31
35
  }
@@ -75,7 +75,7 @@ export async function discardJob(jobId, ctx) {
75
75
  const validJob = job;
76
76
  const idx = shardIndex(validJob.queue);
77
77
  const fromProcessing = location.type === 'processing';
78
- const entry = await withWriteLock(ctx.shardLocks[idx], () => {
78
+ await withWriteLock(ctx.shardLocks[idx], () => {
79
79
  const shard = ctx.shards[idx];
80
80
  if (fromProcessing) {
81
81
  shard.releaseJobResources(validJob.queue, validJob.uniqueKey, validJob.groupId, validJob.id);
@@ -86,9 +86,14 @@ export async function discardJob(jobId, ctx) {
86
86
  }
87
87
  const dlqEntry = shard.addToDlq(validJob);
88
88
  ctx.jobIndex.set(jobId, { type: 'dlq', queueName: validJob.queue });
89
- return dlqEntry;
89
+ // SQLite writes are synchronous. Keeping them in this critical section
90
+ // prevents a concurrent permanent removal from racing a late DLQ insert.
91
+ ctx.storage?.saveDlqEntry(dlqEntry);
92
+ ctx.storage?.deleteJob(jobId);
93
+ ctx.dependencyResults.releaseConsumer(jobId);
94
+ if (validJob.customId && ctx.customIdMap.get(validJob.customId) === jobId) {
95
+ ctx.customIdMap.delete(validJob.customId);
96
+ }
90
97
  });
91
- ctx.storage?.saveDlqEntry(entry);
92
- ctx.storage?.deleteJob(jobId);
93
98
  return true;
94
99
  }
@@ -3,13 +3,18 @@
3
3
  * Job pull logic with timeout support
4
4
  */
5
5
  import type { Job } from '../../domain/types/job';
6
+ import { type GroupPullOptions } from '../../domain/types/group';
6
7
  import { type PullContext } from './pullStateTransition';
7
8
  export type { PullContext } from './pullStateTransition';
9
+ interface PullRequestOptions {
10
+ signal?: AbortSignal;
11
+ group?: GroupPullOptions;
12
+ }
8
13
  /**
9
14
  * Pull next job from queue
10
15
  */
11
- export declare function pullJob(queue: string, timeoutMs: number, ctx: PullContext, signal?: AbortSignal): Promise<Job | null>;
16
+ export declare function pullJob(queue: string, timeoutMs: number, ctx: PullContext, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job | null>;
12
17
  /**
13
18
  * Pull multiple jobs from queue
14
19
  */
15
- export declare function pullJobBatch(queue: string, count: number, timeoutMs: number, ctx: PullContext, signal?: AbortSignal): Promise<Job[]>;
20
+ export declare function pullJobBatch(queue: string, count: number, timeoutMs: number, ctx: PullContext, options?: PullRequestOptions): Promise<Job[]>;