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
@@ -0,0 +1,273 @@
1
+ import { PostgresQueueStore, } from '../../infrastructure/persistence/postgres';
2
+ import { QueueManager } from '../queueManager';
3
+ import { stopBackgroundTasks } from '../backgroundTasks';
4
+ import { PostgresDeferredWriteQueue, throwDeferredWriteErrors } from './deferredWrites';
5
+ import { applyPostgresEventMetrics, hydratePostgresLifetimeMetrics, postgresEventType, } from './lifetimeMetrics';
6
+ import { PostgresQueueSnapshot } from './snapshot';
7
+ import { PostgresStartupEventBuffer } from './startupEventBuffer';
8
+ import { PostgresOperationGate } from './operationGate';
9
+ import { applyPostgresJobProjection, PostgresProjectionRefreshes } from './projectionRefreshes';
10
+ export class PostgresQueueManagerState extends QueueManager {
11
+ postgresStore;
12
+ postgresSnapshot;
13
+ activeTokens = new Map();
14
+ postgresReady;
15
+ refreshes = new Map();
16
+ dirtyQueues = new Set();
17
+ queueEventVersions = new Map();
18
+ snapshotEventBuffer = new PostgresStartupEventBuffer();
19
+ terminalMetricBaselineCommitSeq = 0;
20
+ unsubscribeEvent;
21
+ unsubscribeInvalidation;
22
+ writes = new PostgresDeferredWriteQueue();
23
+ operations;
24
+ projectionRefreshes;
25
+ shutdownPromise = null;
26
+ shutdownComplete = false;
27
+ baseStopped = false;
28
+ stopQueueRefreshes = false;
29
+ constructor(config) {
30
+ const { postgres, ...baseConfig } = config;
31
+ super(baseConfig);
32
+ if (this.backgroundTaskHandles)
33
+ stopBackgroundTasks(this.backgroundTaskHandles);
34
+ this.postgresSnapshot = new PostgresQueueSnapshot(this.config.maxCompletedJobs, this.config.maxJobResults);
35
+ this.postgresStore = new PostgresQueueStore({
36
+ ...postgres,
37
+ maxQueueEvents: this.config.maxQueueEvents,
38
+ maxMetricDataPoints: this.config.maxMetricDataPoints,
39
+ maxCompletedJobs: this.config.maxCompletedJobs,
40
+ maxJobResults: this.config.maxJobResults,
41
+ });
42
+ this.operations = new PostgresOperationGate(this.postgresStore.config.maxConcurrentOperations, this.postgresStore.config.maxQueuedOperations);
43
+ this.projectionRefreshes = new PostgresProjectionRefreshes((requests) => this.postgresStore.loadJobProjections(requests), (id, projection) => applyPostgresJobProjection(this.postgresSnapshot, this.activeTokens, id, projection), (queue, id, error) => this.postgresStore.reportProjectionRefresh(queue, id, error), this.postgresStore.config.pollIntervalMs);
44
+ this.unsubscribeEvent = this.postgresStore.onEvent((event) => this.onStoreEvent(event));
45
+ this.unsubscribeInvalidation = this.postgresStore.onInvalidation((queue) => {
46
+ this.scheduleQueueRefresh(queue);
47
+ });
48
+ this.postgresReady = this.initializePostgres();
49
+ }
50
+ async waitUntilReady() {
51
+ await this.postgresReady;
52
+ }
53
+ async flushPostgresWrites() {
54
+ await this.postgresReady;
55
+ await this.writes.flush();
56
+ }
57
+ async shutdownPostgres() {
58
+ if (this.shutdownComplete)
59
+ return;
60
+ if (!this.shutdownPromise) {
61
+ const attempt = this.performPostgresShutdown()
62
+ .then(() => {
63
+ this.shutdownComplete = true;
64
+ })
65
+ .finally(() => {
66
+ if (this.shutdownPromise === attempt && !this.shutdownComplete) {
67
+ this.shutdownPromise = null;
68
+ }
69
+ });
70
+ this.shutdownPromise = attempt;
71
+ }
72
+ await this.shutdownPromise;
73
+ }
74
+ shutdown() {
75
+ void this.shutdownPostgres().catch(() => undefined);
76
+ }
77
+ async performPostgresShutdown() {
78
+ this.stopQueueRefreshes = true;
79
+ this.dirtyQueues.clear();
80
+ this.projectionRefreshes.close();
81
+ const operationDrain = this.operations.closeAndDrain();
82
+ await operationDrain;
83
+ this.stopBaseRuntime();
84
+ this.unsubscribeEvent();
85
+ this.unsubscribeInvalidation();
86
+ const errors = await this.writes.closeAndDrain();
87
+ try {
88
+ await this.postgresReady;
89
+ }
90
+ catch (error) {
91
+ errors.push(error);
92
+ }
93
+ await Promise.allSettled([...this.refreshes.values(), this.projectionRefreshes.drain()]);
94
+ try {
95
+ await this.postgresStore.close();
96
+ }
97
+ catch (error) {
98
+ errors.push(error);
99
+ }
100
+ throwDeferredWriteErrors(errors, 'PostgreSQL shutdown failed');
101
+ }
102
+ tokenFor(id, token) {
103
+ return token ?? this.activeTokens.get(id) ?? this.postgresSnapshot.get(id)?.token ?? null;
104
+ }
105
+ forgetToken(id) {
106
+ this.activeTokens.delete(id);
107
+ }
108
+ runPostgresOperation(operation) {
109
+ return this.operations.run(operation);
110
+ }
111
+ async refreshJob(id, queue) {
112
+ const targetQueue = queue ?? this.postgresSnapshot.get(id)?.job.queue ?? '';
113
+ try {
114
+ await this.projectionRefreshes.refreshNow(id, targetQueue);
115
+ }
116
+ catch {
117
+ this.projectionRefreshes.request(id, targetQueue);
118
+ }
119
+ }
120
+ async fetchPostgresJob(id) {
121
+ const queue = this.postgresSnapshot.get(id)?.job.queue ?? '';
122
+ return (await this.projectionRefreshes.refreshNow(id, queue)).row;
123
+ }
124
+ async refreshJobs(ids, queue) {
125
+ const requests = [...new Set(ids)].map((id) => ({
126
+ id,
127
+ queue: queue ?? this.postgresSnapshot.get(id)?.job.queue ?? '',
128
+ }));
129
+ try {
130
+ await this.projectionRefreshes.refreshManyNow(requests);
131
+ }
132
+ catch {
133
+ for (const request of requests)
134
+ this.projectionRefreshes.request(request.id, request.queue);
135
+ }
136
+ }
137
+ async refreshQueue(queue) {
138
+ const eventVersion = this.queueEventVersions.get(queue) ?? 0;
139
+ const { rows, state, exists, results } = await this.postgresStore.loadQueueReadModel(queue);
140
+ if (eventVersion !== (this.queueEventVersions.get(queue) ?? 0)) {
141
+ this.dirtyQueues.add(queue);
142
+ return false;
143
+ }
144
+ this.projectionRefreshes.supersedeQueue(queue);
145
+ if (!exists) {
146
+ for (const id of this.postgresSnapshot.removeQueue(queue))
147
+ this.activeTokens.delete(id);
148
+ return true;
149
+ }
150
+ this.postgresSnapshot.replaceQueue(queue, rows, state, results);
151
+ return true;
152
+ }
153
+ async refreshQueueAfterCommit(queue) {
154
+ try {
155
+ if (!(await this.refreshQueue(queue)))
156
+ this.scheduleQueueRefresh(queue);
157
+ else
158
+ this.postgresStore.reportQueueRefresh(queue, null);
159
+ }
160
+ catch (error) {
161
+ this.postgresStore.reportQueueRefresh(queue, error);
162
+ this.scheduleQueueRefresh(queue);
163
+ }
164
+ }
165
+ enqueueWrite(operation) {
166
+ this.writes.enqueue(operation);
167
+ }
168
+ async initializePostgres() {
169
+ await this.postgresStore.initialize();
170
+ for (let attempt = 0; attempt < 2; attempt++) {
171
+ const buffer = this.snapshotEventBuffer;
172
+ if (!buffer)
173
+ return;
174
+ buffer.reset();
175
+ const { rows, results, crons, states } = await this.postgresStore.loadManagerSnapshot();
176
+ const events = buffer.take();
177
+ if (!events && attempt === 0)
178
+ continue;
179
+ this.postgresSnapshot.hydrate(rows);
180
+ this.postgresSnapshot.hydrateResults(results);
181
+ this.cronScheduler.load([...crons]);
182
+ for (const state of states)
183
+ this.postgresSnapshot.setQueueState(state);
184
+ for (const event of events ?? []) {
185
+ this.postgresSnapshot.apply(event);
186
+ applyPostgresEventMetrics(this.metrics, this.perQueueMetrics, event, false);
187
+ }
188
+ await this.postgresStore.finalizeLifetimeMetrics((lifetimeMetrics) => {
189
+ hydratePostgresLifetimeMetrics(this.metrics, this.perQueueMetrics, lifetimeMetrics);
190
+ this.terminalMetricBaselineCommitSeq = lifetimeMetrics.baselineCommitSeq;
191
+ this.snapshotEventBuffer = null;
192
+ this.projectionRefreshes.start();
193
+ });
194
+ return;
195
+ }
196
+ }
197
+ scheduleQueueRefresh(queue) {
198
+ if (this.stopQueueRefreshes)
199
+ return;
200
+ this.dirtyQueues.add(queue);
201
+ if (this.refreshes.has(queue))
202
+ return;
203
+ const refresh = this.postgresReady
204
+ .then(() => this.refreshDirtyQueue(queue))
205
+ .catch(() => {
206
+ this.dirtyQueues.delete(queue);
207
+ })
208
+ .finally(() => {
209
+ this.refreshes.delete(queue);
210
+ if (this.dirtyQueues.has(queue))
211
+ this.scheduleQueueRefresh(queue);
212
+ });
213
+ this.refreshes.set(queue, refresh);
214
+ }
215
+ async refreshDirtyQueue(queue) {
216
+ let retryDelay = this.postgresStore.config.pollIntervalMs;
217
+ while (!this.stopQueueRefreshes && this.dirtyQueues.delete(queue)) {
218
+ try {
219
+ const applied = await this.refreshQueue(queue);
220
+ if (!applied && !this.stopQueueRefreshes) {
221
+ await Bun.sleep(this.postgresStore.config.pollIntervalMs);
222
+ }
223
+ this.postgresStore.reportQueueRefresh(queue, null);
224
+ retryDelay = this.postgresStore.config.pollIntervalMs;
225
+ }
226
+ catch (error) {
227
+ this.postgresStore.reportQueueRefresh(queue, error);
228
+ if (this.stopQueueRefreshes)
229
+ return;
230
+ this.dirtyQueues.add(queue);
231
+ await Bun.sleep(retryDelay);
232
+ retryDelay = Math.min(retryDelay * 2, 1_000);
233
+ }
234
+ }
235
+ }
236
+ onStoreEvent(event) {
237
+ this.queueEventVersions.set(event.queue, (this.queueEventVersions.get(event.queue) ?? 0) + 1);
238
+ const startupBuffer = this.snapshotEventBuffer;
239
+ startupBuffer?.capture(event);
240
+ if (startupBuffer)
241
+ this.postgresSnapshot.apply(event);
242
+ if (startupBuffer?.overflowed)
243
+ this.scheduleQueueRefresh(event.queue);
244
+ else
245
+ this.projectionRefreshes.request(event.jobId, event.queue);
246
+ const mapped = postgresEventType(event.type);
247
+ if (!mapped)
248
+ return;
249
+ if (!startupBuffer) {
250
+ applyPostgresEventMetrics(this.metrics, this.perQueueMetrics, event, event.commitSeq > this.terminalMetricBaselineCommitSeq);
251
+ }
252
+ this.eventsManager.broadcast({
253
+ eventType: mapped,
254
+ queue: event.queue,
255
+ jobId: event.jobId,
256
+ timestamp: event.occurredAt,
257
+ ...(Object.hasOwn(event, 'result') && { data: event.result }),
258
+ ...(event.error !== undefined && { error: event.error }),
259
+ ...(mapped === 'failed' && { terminal: event.state === 'failed' }),
260
+ });
261
+ }
262
+ applyPostgresClaim(claim) {
263
+ this.projectionRefreshes.supersede(claim.job.id);
264
+ this.activeTokens.set(claim.job.id, claim.token);
265
+ this.postgresSnapshot.claim(claim);
266
+ }
267
+ stopBaseRuntime() {
268
+ if (this.baseStopped)
269
+ return;
270
+ this.baseStopped = true;
271
+ super.shutdown();
272
+ }
273
+ }
@@ -0,0 +1,20 @@
1
+ import { FailureReason } from '../../domain/types/dlq';
2
+ import type { JobId } from '../../domain/types/job';
3
+ import type { AckBatchOutcome, AckOutcome, CompletionOptions } from '../types/ack';
4
+ import { PostgresQueueManagerQueries } from './queries';
5
+ /** Terminal delivery transitions drained before the PostgreSQL pool closes. */
6
+ export declare class PostgresQueueManagerTerminalDelivery extends PostgresQueueManagerQueries {
7
+ ack(id: JobId, result?: unknown, token?: string, options?: CompletionOptions): Promise<AckOutcome>;
8
+ ackBatch(ids: JobId[], tokens?: string[]): Promise<AckBatchOutcome>;
9
+ ackBatchWithResults(items: Array<{
10
+ id: JobId;
11
+ result: unknown;
12
+ token?: string;
13
+ } & CompletionOptions>): Promise<AckBatchOutcome>;
14
+ fail(id: JobId, error?: string, token?: string, unrecoverable?: boolean, stack?: string[], removeOnFail?: boolean): Promise<AckOutcome>;
15
+ failWithReason(id: JobId, error: string | undefined, reason: FailureReason): Promise<AckOutcome>;
16
+ private requireToken;
17
+ private ackPostgres;
18
+ private completeBatch;
19
+ private failPostgres;
20
+ }
@@ -0,0 +1,100 @@
1
+ import { applyPostgresBatchCompletion } from './batchSnapshot';
2
+ import { PostgresQueueManagerQueries } from './queries';
3
+ /** Terminal delivery transitions drained before the PostgreSQL pool closes. */
4
+ export class PostgresQueueManagerTerminalDelivery extends PostgresQueueManagerQueries {
5
+ async ack(id, result, token, options = {}) {
6
+ return await this.runPostgresOperation(() => this.ackPostgres(id, result, token, options));
7
+ }
8
+ async ackBatch(ids, tokens) {
9
+ return await this.runPostgresOperation(() => this.completeBatch(ids.map((id, index) => ({ id, token: tokens?.[index] }))));
10
+ }
11
+ async ackBatchWithResults(items) {
12
+ return await this.runPostgresOperation(() => this.completeBatch(items));
13
+ }
14
+ // oxlint-disable-next-line max-params -- public compatibility signature carries failure policy
15
+ async fail(id, error, token, unrecoverable = false, stack, removeOnFail) {
16
+ return await this.runPostgresOperation(() => this.failPostgres(id, error, token, { unrecoverable, stack, removeOnFail }));
17
+ }
18
+ async failWithReason(id, error, reason) {
19
+ return await this.runPostgresOperation(() => this.failPostgres(id, error, undefined, {
20
+ unrecoverable: reason === "timeout" /* FailureReason.Timeout */,
21
+ failureReason: reason,
22
+ }));
23
+ }
24
+ requireToken(id, supplied) {
25
+ const token = this.tokenFor(id, supplied);
26
+ if (!token)
27
+ throw new Error(`Lock token required for job ${String(id)}`);
28
+ return token;
29
+ }
30
+ async ackPostgres(id, result, token, options) {
31
+ await this.postgresReady;
32
+ const transition = await this.postgresStore.complete(id, this.requireToken(id, token), result, options.removeOnComplete);
33
+ this.forgetToken(id);
34
+ await this.refreshJob(id);
35
+ if (transition.applied)
36
+ return;
37
+ if (transition.alreadyFinalized)
38
+ return { applied: false, reason: 'already-finalized' };
39
+ throw new Error(`Invalid or expired lock token for job ${String(id)}`);
40
+ }
41
+ async completeBatch(items) {
42
+ if (items.length === 0)
43
+ return;
44
+ if (new Set(items.map((item) => String(item.id))).size === items.length) {
45
+ await this.postgresReady;
46
+ const transitions = await this.postgresStore.completeMany(items.map((item) => ({
47
+ id: item.id,
48
+ token: this.requireToken(item.id, item.token),
49
+ result: item.result,
50
+ removeOnComplete: item.removeOnComplete,
51
+ })));
52
+ const repeatQueues = new Set();
53
+ const ignoredIds = [];
54
+ const ignoredIndices = [];
55
+ for (let index = 0; index < transitions.length; index++) {
56
+ const transition = transitions[index];
57
+ this.forgetToken(items[index].id);
58
+ const repeatQueue = applyPostgresBatchCompletion(this.postgresSnapshot, items[index], transition);
59
+ if (repeatQueue)
60
+ repeatQueues.add(repeatQueue);
61
+ if (!transition.applied) {
62
+ ignoredIndices.push(index);
63
+ ignoredIds.push(items[index].id);
64
+ }
65
+ }
66
+ await Promise.all([
67
+ ...ignoredIds.map((id) => this.refreshJob(id)),
68
+ ...[...repeatQueues].map((queue) => this.refreshQueueAfterCommit(queue)),
69
+ ]);
70
+ return ignoredIndices.length === 0
71
+ ? undefined
72
+ : { ignoredIndices, ignoredIds: ignoredIndices.map((index) => items[index].id) };
73
+ }
74
+ const ignoredIndices = [];
75
+ for (let index = 0; index < items.length; index++) {
76
+ const outcome = await this.ackPostgres(items[index].id, items[index].result, items[index].token, items[index]);
77
+ if (outcome)
78
+ ignoredIndices.push(index);
79
+ }
80
+ return ignoredIndices.length === 0
81
+ ? undefined
82
+ : { ignoredIndices, ignoredIds: ignoredIndices.map((index) => items[index].id) };
83
+ }
84
+ async failPostgres(id, error, token, options) {
85
+ await this.postgresReady;
86
+ const transition = await this.postgresStore.fail({
87
+ id,
88
+ token: this.requireToken(id, token),
89
+ error,
90
+ ...options,
91
+ });
92
+ this.forgetToken(id);
93
+ await this.refreshJob(id);
94
+ if (transition.applied)
95
+ return;
96
+ if (transition.alreadyFinalized)
97
+ return { applied: false, reason: 'already-finalized' };
98
+ throw new Error(`Invalid or expired lock token for job ${String(id)}`);
99
+ }
100
+ }
@@ -0,0 +1,2 @@
1
+ export { PostgresQueueManagerOperations as PostgresQueueManager } from './postgres-queue-manager/operations';
2
+ export type { PostgresQueueManagerConfig } from './postgres-queue-manager/config';
@@ -0,0 +1 @@
1
+ export { PostgresQueueManagerOperations as PostgresQueueManager } from './postgres-queue-manager/operations';
@@ -95,6 +95,7 @@ export class QueueManagerControl extends QueueManagerQueries {
95
95
  this.perQueueMetrics.delete(queue);
96
96
  this.telemetryJournal.clearQueue(queue);
97
97
  this.storage?.deleteQueueState(queue);
98
+ this.storage?.deleteGroupState(queue);
98
99
  }
99
100
  listQueues() {
100
101
  return Array.from(this.queueNamesCache);
@@ -1,17 +1,18 @@
1
1
  import type { Job, JobId, JobInput, JobLock } from '../../domain/types/job';
2
2
  import type { AtomicFlowBatchInput, AtomicFlowBatchResult } from '../../domain/types/flow';
3
+ import type { GroupPullOptions } from '../../domain/types/group';
3
4
  import { QueueManagerState } from './state';
4
5
  export declare class QueueManagerDelivery extends QueueManagerState {
5
6
  push(queue: string, input: JobInput): Promise<Job>;
6
7
  pushBatch(queue: string, inputs: JobInput[]): Promise<JobId[]>;
7
8
  pushFlow(batch: AtomicFlowBatchInput): Promise<AtomicFlowBatchResult>;
8
- pull(queue: string, timeoutMs?: number, signal?: AbortSignal): Promise<Job | null>;
9
- pullWithLock(queue: string, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal): Promise<{
9
+ pull(queue: string, timeoutMs?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job | null>;
10
+ pullWithLock(queue: string, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<{
10
11
  job: Job | null;
11
12
  token: string | null;
12
13
  }>;
13
- pullBatch(queue: string, count: number, timeoutMs?: number, signal?: AbortSignal): Promise<Job[]>;
14
- pullBatchWithLock(queue: string, count: number, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal): Promise<{
14
+ pullBatch(queue: string, count: number, timeoutMs?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<Job[]>;
15
+ pullBatchWithLock(queue: string, count: number, owner: string, timeoutMs?: number, lockTtl?: number, signal?: AbortSignal, groupOptions?: GroupPullOptions): Promise<{
15
16
  jobs: Job[];
16
17
  tokens: string[];
17
18
  }>;
@@ -20,29 +20,36 @@ export class QueueManagerDelivery extends QueueManagerState {
20
20
  async pushFlow(batch) {
21
21
  return pushFlowBatch(batch, this.contextFactory.getPushContext());
22
22
  }
23
- async pull(queue, timeoutMs = 0, signal) {
24
- const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal);
23
+ async pull(queue, timeoutMs = 0, signal, groupOptions) {
24
+ const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal, groupOptions);
25
25
  if (job)
26
26
  this.scheduleJobTimeout(job);
27
27
  return job;
28
28
  }
29
- async pullWithLock(queue, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal) {
30
- const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal);
29
+ // oxlint-disable-next-line max-params -- public API includes cancellation and lock policy
30
+ async pullWithLock(queue, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal, groupOptions) {
31
+ const job = await pullJob(queue, timeoutMs, this.contextFactory.getPullContext(), signal, groupOptions);
31
32
  if (!job)
32
33
  return { job: null, token: null };
33
34
  const token = lockMgr.createLock(job.id, owner, this.contextFactory.getLockContext(), lockTtl);
34
35
  this.scheduleJobTimeout(job);
35
36
  return { job, token };
36
37
  }
37
- async pullBatch(queue, count, timeoutMs = 0, signal) {
38
- const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(), signal);
38
+ async pullBatch(queue, count, timeoutMs = 0, signal, groupOptions) {
39
+ const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(), {
40
+ signal,
41
+ group: groupOptions,
42
+ });
39
43
  for (const job of jobs)
40
44
  this.scheduleJobTimeout(job);
41
45
  return jobs;
42
46
  }
43
47
  // oxlint-disable-next-line max-params -- public API includes cancellation and lock policy
44
- async pullBatchWithLock(queue, count, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal) {
45
- const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(), signal);
48
+ async pullBatchWithLock(queue, count, owner, timeoutMs = 0, lockTtl = DEFAULT_LOCK_TTL, signal, groupOptions) {
49
+ const jobs = await pullJobBatch(queue, count, timeoutMs, this.contextFactory.getPullContext(), {
50
+ signal,
51
+ group: groupOptions,
52
+ });
46
53
  const tokens = jobs.map((job) => lockMgr.createLock(job.id, owner, this.contextFactory.getLockContext(), lockTtl) ?? '');
47
54
  for (const job of jobs)
48
55
  this.scheduleJobTimeout(job);
@@ -9,6 +9,10 @@ export class QueueManagerFlowFailures extends QueueManagerDependencyRuntime {
9
9
  this.jobIndex.delete(entry.job.id);
10
10
  this.jobResults.delete(entry.job.id);
11
11
  this.jobLogs.delete(entry.job.id);
12
+ this.dependencyResults.releaseConsumer(entry.job.id);
13
+ if (entry.job.customId && this.customIdMap.get(entry.job.customId) === entry.job.id) {
14
+ this.customIdMap.delete(entry.job.customId);
15
+ }
12
16
  }
13
17
  this.storage?.purgeDlqEntries(entry.job.queue, [entry.job.id], ownsTerminal ? [entry.job.id] : [], false);
14
18
  }
@@ -1,7 +1,18 @@
1
1
  import type { Job, JobId } from '../../domain/types/job';
2
2
  import type { DlqEntry, DlqFilter, DlqStats } from '../../domain/types/dlq';
3
3
  import { QueueManagerControl } from './control';
4
+ import { type GroupRateLimitOverride } from '../../domain/types/group';
4
5
  export declare class QueueManagerLimits extends QueueManagerControl {
6
+ getGroupJobsCount(queue: string, groupId: string): number | Promise<number>;
7
+ getGroupsJobsCount(queue: string): number | Promise<number>;
8
+ getGroupActiveCount(queue: string, groupId: string): number | Promise<number>;
9
+ setGroupRateLimit(queue: string, groupId: string, max: number, duration: number): void | Promise<void>;
10
+ getGroupRateLimit(queue: string, groupId: string): GroupRateLimitOverride | null | Promise<GroupRateLimitOverride | null>;
11
+ removeGroupRateLimit(queue: string, groupId: string): number | Promise<number>;
12
+ getGroupRateLimitTtl(queue: string, groupId: string, maxJobs?: number): number | Promise<number>;
13
+ setGroupConcurrency(queue: string, groupId: string, concurrency: number): void | Promise<void>;
14
+ getGroupConcurrency(queue: string, groupId: string): number | null | Promise<number | null>;
15
+ removeGroupConcurrency(queue: string, groupId: string): number | Promise<number>;
5
16
  getCountsPerPriority(queue: string): Record<number, number>;
6
17
  getJobs(queue: string, options?: {
7
18
  state?: string | string[];
@@ -16,6 +27,8 @@ export declare class QueueManagerLimits extends QueueManagerControl {
16
27
  retryDlq(queue: string, jobId?: JobId, limit?: number): number;
17
28
  retryDlqByFilter(queue: string, filter: DlqFilter): number;
18
29
  purgeDlq(queue: string): number;
30
+ /** Remove one terminal DLQ job without re-enqueuing it. */
31
+ removeDlqJob(queue: string, jobId: JobId): boolean;
19
32
  retryCompleted(queue: string, jobId?: JobId, options?: {
20
33
  limit?: number;
21
34
  timestamp?: number;
@@ -4,7 +4,68 @@ import { shardIndex, SHARD_COUNT } from '../../shared/hash';
4
4
  import * as dlqOps from '../dlqManager';
5
5
  import * as queryOps from '../operations/queryOperations';
6
6
  import { QueueManagerControl } from './control';
7
+ import { assertGroupId, assertPositiveSafeInteger, } from '../../domain/types/group';
7
8
  export class QueueManagerLimits extends QueueManagerControl {
9
+ getGroupJobsCount(queue, groupId) {
10
+ assertGroupId(groupId);
11
+ return this.shards[shardIndex(queue)].getGroupJobsCount(queue, groupId);
12
+ }
13
+ getGroupsJobsCount(queue) {
14
+ return this.shards[shardIndex(queue)].getGroupsJobsCount(queue);
15
+ }
16
+ getGroupActiveCount(queue, groupId) {
17
+ assertGroupId(groupId);
18
+ return this.shards[shardIndex(queue)].getGroupActiveCount(queue, groupId);
19
+ }
20
+ setGroupRateLimit(queue, groupId, max, duration) {
21
+ assertGroupId(groupId);
22
+ assertPositiveSafeInteger(max, 'max');
23
+ assertPositiveSafeInteger(duration, 'duration');
24
+ const shard = this.shards[shardIndex(queue)];
25
+ this.storage?.saveGroupRateLimit(queue, groupId, max, duration);
26
+ shard.setGroupRateLimit(queue, groupId, max, duration);
27
+ shard.notifyBatch(queue, Math.max(1, shard.getGroupJobsCount(queue, groupId)));
28
+ }
29
+ getGroupRateLimit(queue, groupId) {
30
+ assertGroupId(groupId);
31
+ return this.shards[shardIndex(queue)].getGroupRateLimit(queue, groupId);
32
+ }
33
+ removeGroupRateLimit(queue, groupId) {
34
+ assertGroupId(groupId);
35
+ const shard = this.shards[shardIndex(queue)];
36
+ if (!shard.getGroupRateLimit(queue, groupId))
37
+ return 0;
38
+ this.storage?.removeGroupRateLimit(queue, groupId);
39
+ const removed = shard.removeGroupRateLimit(queue, groupId);
40
+ shard.notifyBatch(queue, Math.max(1, shard.getGroupJobsCount(queue, groupId)));
41
+ return removed;
42
+ }
43
+ getGroupRateLimitTtl(queue, groupId, maxJobs) {
44
+ assertGroupId(groupId);
45
+ return this.shards[shardIndex(queue)].getGroupRateLimitTtl(queue, groupId, maxJobs);
46
+ }
47
+ setGroupConcurrency(queue, groupId, concurrency) {
48
+ assertGroupId(groupId);
49
+ assertPositiveSafeInteger(concurrency, 'concurrency');
50
+ const shard = this.shards[shardIndex(queue)];
51
+ this.storage?.saveGroupConcurrency(queue, groupId, concurrency);
52
+ shard.setGroupConcurrency(queue, groupId, concurrency);
53
+ shard.notifyBatch(queue, Math.max(1, shard.getGroupJobsCount(queue, groupId)));
54
+ }
55
+ getGroupConcurrency(queue, groupId) {
56
+ assertGroupId(groupId);
57
+ return this.shards[shardIndex(queue)].getGroupConcurrency(queue, groupId);
58
+ }
59
+ removeGroupConcurrency(queue, groupId) {
60
+ assertGroupId(groupId);
61
+ const shard = this.shards[shardIndex(queue)];
62
+ if (shard.getGroupConcurrency(queue, groupId) === null)
63
+ return 0;
64
+ this.storage?.removeGroupConcurrency(queue, groupId);
65
+ const removed = shard.removeGroupConcurrency(queue, groupId);
66
+ shard.notifyBatch(queue, Math.max(1, shard.getGroupJobsCount(queue, groupId)));
67
+ return removed;
68
+ }
8
69
  getCountsPerPriority(queue) {
9
70
  const counts = this.shards[shardIndex(queue)].getCountsPerPriority(queue);
10
71
  return Object.fromEntries(counts);
@@ -37,6 +98,10 @@ export class QueueManagerLimits extends QueueManagerControl {
37
98
  purgeDlq(queue) {
38
99
  return dlqOps.purgeDlqJobs(queue, this.contextFactory.getDlqContext());
39
100
  }
101
+ /** Remove one terminal DLQ job without re-enqueuing it. */
102
+ removeDlqJob(queue, jobId) {
103
+ return dlqOps.removeDlqJob(queue, jobId, this.contextFactory.getDlqContext());
104
+ }
40
105
  retryCompleted(queue, jobId, options) {
41
106
  return dlqOps.retryCompletedJobs(queue, this.contextFactory.getRetryCompletedContext(), jobId, options);
42
107
  }
@@ -2,6 +2,7 @@ import * as logsOps from '../jobLogsManager';
2
2
  import { generatePrometheusMetrics } from '../metricsExporter';
3
3
  import { selectPrometheusQueues } from '../prometheusOperationalMetrics';
4
4
  import * as statsMgr from '../statsManager';
5
+ import { isStorageDegraded } from '../../shared/storageHealth';
5
6
  import { QueueManagerStats } from './stats';
6
7
  export class QueueManagerObservability extends QueueManagerStats {
7
8
  getQueueMetrics(queue, type, start = 0, end = -1) {
@@ -25,9 +26,20 @@ export class QueueManagerObservability extends QueueManagerStats {
25
26
  getPrometheusMetrics() {
26
27
  const storageStatus = this.getStorageStatus();
27
28
  const memory = process.memoryUsage();
28
- const queueSelection = selectPrometheusQueues(this.queueNamesCache, this.config.maxPrometheusQueues);
29
- return generatePrometheusMetrics(this.getStats(), this.workerManager, this.webhookManager, statsMgr.getPerQueueStats(this.contextFactory.getStatsContext(), queueSelection.selected), {
30
- storageDegraded: storageStatus.diskFull,
29
+ const queueSelection = selectPrometheusQueues(this.listQueues(), this.config.maxPrometheusQueues);
30
+ const countsByQueue = this.getQueueJobCountsBatch(queueSelection.selected);
31
+ const perQueueStats = new Map([...countsByQueue].map(([queue, counts]) => [
32
+ queue,
33
+ {
34
+ waiting: counts.waiting,
35
+ prioritized: counts.prioritized,
36
+ delayed: counts.delayed,
37
+ active: counts.active,
38
+ dlq: counts.failed,
39
+ },
40
+ ]));
41
+ return generatePrometheusMetrics(this.getStats(), this.workerManager, this.webhookManager, perQueueStats, {
42
+ storageDegraded: isStorageDegraded(storageStatus),
31
43
  storageDiskFull: storageStatus.diskFull,
32
44
  ...(this.storage && { sqliteDatabaseSizeBytes: this.storage.getSize() }),
33
45
  processHeapUsedBytes: memory.heapUsed,
@@ -4,6 +4,13 @@ export declare class QueueManagerQueries extends QueueManagerLocks {
4
4
  getJob(jobId: JobId): Promise<Job | null>;
5
5
  getJobState(jobId: JobId): Promise<string>;
6
6
  getResult(jobId: JobId): unknown;
7
+ /** Distinguish a completed generation from a valid undefined result. */
8
+ getCompletionAsync(jobId: JobId): Promise<{
9
+ found: boolean;
10
+ result: unknown;
11
+ }>;
12
+ /** Async result port used by transports; memory and SQLite remain synchronous internally. */
13
+ getResultAsync(jobId: JobId): Promise<unknown>;
7
14
  getChildrenValues(parentJobId: JobId): Promise<Record<string, unknown>>;
8
15
  updateJobParent(childJobId: JobId, parentJobId: JobId): Promise<void>;
9
16
  getJobByCustomId(customId: string): Job | null;
@@ -14,6 +14,15 @@ export class QueueManagerQueries extends QueueManagerLocks {
14
14
  getResult(jobId) {
15
15
  return queryOps.getJobResult(jobId, this.contextFactory.getQueryContext());
16
16
  }
17
+ /** Distinguish a completed generation from a valid undefined result. */
18
+ async getCompletionAsync(jobId) {
19
+ const found = this.completedJobs.has(jobId);
20
+ return { found, result: found ? this.getResult(jobId) : undefined };
21
+ }
22
+ /** Async result port used by transports; memory and SQLite remain synchronous internally. */
23
+ async getResultAsync(jobId) {
24
+ return (await this.getCompletionAsync(jobId)).result;
25
+ }
17
26
  async getChildrenValues(parentJobId) {
18
27
  const job = await this.getJob(parentJobId);
19
28
  if (!job?.childrenIds || job.childrenIds.length === 0)