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
@@ -1,6 +1,6 @@
1
1
  import type { ListWorkersCommand, RegisterWorkerCommand, UnregisterWorkerCommand } from '../../../../domain/types/command';
2
2
  import type { Response } from '../../../../domain/types/response';
3
3
  import type { HandlerContext } from '../../types';
4
- export declare function handleRegisterWorker(command: RegisterWorkerCommand, context: HandlerContext, requestId?: string): Response;
5
- export declare function handleUnregisterWorker(command: UnregisterWorkerCommand, context: HandlerContext, requestId?: string): Response;
6
- export declare function handleListWorkers(_command: ListWorkersCommand, context: HandlerContext, requestId?: string): Response;
4
+ export declare function handleRegisterWorker(command: RegisterWorkerCommand, context: HandlerContext, requestId?: string): Response | Promise<Response>;
5
+ export declare function handleUnregisterWorker(command: UnregisterWorkerCommand, context: HandlerContext, requestId?: string): Response | Promise<Response>;
6
+ export declare function handleListWorkers(_command: ListWorkersCommand, context: HandlerContext, requestId?: string): Response | Promise<Response>;
@@ -4,14 +4,15 @@ function computeWorkerStatus(lastSeen, now) {
4
4
  return now - lastSeen < WORKER_TIMEOUT_MS ? 'active' : 'stale';
5
5
  }
6
6
  export function handleRegisterWorker(command, context, requestId) {
7
- const worker = context.queueManager.registerWorker(command.name, command.queues, command.concurrency, {
7
+ const manager = context.queueManager;
8
+ const options = {
8
9
  workerId: command.workerId,
9
10
  hostname: command.hostname,
10
11
  pid: command.pid,
11
12
  startedAt: command.startedAt,
12
13
  clientId: context.clientId,
13
- });
14
- return response.data({
14
+ };
15
+ const complete = (worker) => response.data({
15
16
  workerId: worker.id,
16
17
  name: worker.name,
17
18
  queues: worker.queues,
@@ -26,15 +27,24 @@ export function handleRegisterWorker(command, context, requestId) {
26
27
  failedJobs: worker.failedJobs,
27
28
  currentJob: worker.currentJob,
28
29
  }, requestId);
30
+ return manager.registerWorkerDurable
31
+ ? manager
32
+ .registerWorkerDurable(command.name, command.queues, command.concurrency, options)
33
+ .then(complete)
34
+ : complete(manager.registerWorker(command.name, command.queues, command.concurrency, options));
29
35
  }
30
36
  export function handleUnregisterWorker(command, context, requestId) {
31
- return context.queueManager.unregisterWorker(command.workerId)
37
+ const manager = context.queueManager;
38
+ const complete = (removed) => removed
32
39
  ? response.data({ removed: true }, requestId)
33
40
  : response.error('Worker not found', requestId);
41
+ return manager.unregisterWorkerDurable
42
+ ? manager.unregisterWorkerDurable(command.workerId, context.clientId).then(complete)
43
+ : complete(manager.unregisterWorker(command.workerId));
34
44
  }
35
- export function handleListWorkers(_command, context, requestId) {
36
- const workers = context.queueManager.workerManager.list();
45
+ function workerListResponse(workers, requestId, lifetime) {
37
46
  const now = Date.now();
47
+ const active = workers.filter((worker) => computeWorkerStatus(worker.lastSeen, now) === 'active');
38
48
  return response.data({
39
49
  workers: workers.map((worker) => ({
40
50
  id: worker.id,
@@ -52,6 +62,20 @@ export function handleListWorkers(_command, context, requestId) {
52
62
  currentJob: worker.currentJob,
53
63
  uptime: now - worker.registeredAt,
54
64
  })),
55
- stats: context.queueManager.workerManager.getStats(),
65
+ stats: {
66
+ total: workers.length,
67
+ active: active.length,
68
+ totalProcessed: lifetime?.totalProcessed ??
69
+ workers.reduce((sum, worker) => sum + worker.processedJobs, 0),
70
+ totalFailed: lifetime?.totalFailed ?? workers.reduce((sum, worker) => sum + worker.failedJobs, 0),
71
+ activeJobs: lifetime?.activeJobs ?? workers.reduce((sum, worker) => sum + worker.activeJobs, 0),
72
+ concurrencySlots: active.reduce((sum, worker) => sum + worker.concurrency, 0),
73
+ },
56
74
  }, requestId);
57
75
  }
76
+ export function handleListWorkers(_command, context, requestId) {
77
+ const manager = context.queueManager;
78
+ return manager.listWorkersDurable
79
+ ? manager.listWorkersDurable().then((workers) => workerListResponse(workers, requestId))
80
+ : workerListResponse(manager.workerManager.list(), requestId, manager.workerManager.getStats());
81
+ }
@@ -6,6 +6,8 @@
6
6
  */
7
7
  import { type JobInput } from '../../../domain/types/job';
8
8
  import type { HandlerContext } from '../types';
9
+ /** Validate PUSH dependencies against the authoritative engine when it exposes one. */
10
+ export declare function validatePushDependencies(dependencies: readonly string[] | undefined, ctx: HandlerContext): string | null | Promise<string | null>;
9
11
  /**
10
12
  * Validate every job of a PUSHB batch. Returns an error message naming the
11
13
  * offending index, or null when the whole batch is valid.
@@ -20,4 +22,4 @@ import type { HandlerContext } from '../types';
20
22
  * can never resolve. jobIndex/completedJobs/depCompletions are hoisted out
21
23
  * of the loop because PUSHB is the bulk hot path.
22
24
  */
23
- export declare function validatePushBatchJobs(jobs: JobInput[], ctx: HandlerContext): string | null;
25
+ export declare function validatePushBatchJobs(jobs: JobInput[], ctx: HandlerContext): string | null | Promise<string | null>;
@@ -4,8 +4,33 @@
4
4
  * validateJobData/validateJobOptions bounds and the same dependsOn
5
5
  * existence gate handlePush enforces (core.ts).
6
6
  */
7
- import { normalizeLegacyJobPayload } from '../../../domain/types/job';
8
- import { validateJobData, validateJobOptions } from '../protocol';
7
+ import { jobId, normalizeLegacyJobPayload, } from '../../../domain/types/job';
8
+ import { validateGroupId, validateJobData, validateJobOptions } from '../protocol';
9
+ function dependencyExistsLocally(id, ctx) {
10
+ return (ctx.queueManager.getJobIndex().has(id) ||
11
+ ctx.queueManager.getCompletedJobs().has(id) ||
12
+ ctx.queueManager.getDepCompletions().has(id));
13
+ }
14
+ /** Validate PUSH dependencies against the authoritative engine when it exposes one. */
15
+ export function validatePushDependencies(dependencies, ctx) {
16
+ if (!dependencies || dependencies.length === 0)
17
+ return null;
18
+ const manager = ctx.queueManager;
19
+ if (!manager.findMissingDependenciesDurable) {
20
+ for (const dependency of dependencies) {
21
+ if (!dependencyExistsLocally(jobId(dependency), ctx)) {
22
+ return `Dependency job not found: ${dependency}`;
23
+ }
24
+ }
25
+ return null;
26
+ }
27
+ const ids = dependencies.map(jobId);
28
+ return manager.findMissingDependenciesDurable(ids).then((missingIds) => {
29
+ const missing = new Set(missingIds.map(String));
30
+ const dependency = dependencies.find((id) => missing.has(String(id)));
31
+ return dependency === undefined ? null : `Dependency job not found: ${dependency}`;
32
+ });
33
+ }
9
34
  /**
10
35
  * Validate every job of a PUSHB batch. Returns an error message naming the
11
36
  * offending index, or null when the whole batch is valid.
@@ -34,6 +59,24 @@ export function validatePushBatchJobs(jobs, ctx) {
34
59
  batchIds.add(job.customId);
35
60
  }
36
61
  }
62
+ const manager = ctx.queueManager;
63
+ if (manager.findMissingDependenciesDurable) {
64
+ const dependencies = jobs.flatMap((job) => (job.dependsOn ?? []).filter((id) => !(batchIds?.has(String(id)) ?? false)));
65
+ if (dependencies.length === 0) {
66
+ return validateJobs(jobs, { jobIndex, completedJobs, depCompletions, batchIds });
67
+ }
68
+ return manager.findMissingDependenciesDurable(dependencies).then((missingIds) => validateJobs(jobs, {
69
+ jobIndex,
70
+ completedJobs,
71
+ depCompletions,
72
+ batchIds,
73
+ missingDependencies: new Set(missingIds),
74
+ }));
75
+ }
76
+ return validateJobs(jobs, { jobIndex, completedJobs, depCompletions, batchIds });
77
+ }
78
+ function validateJobs(jobs, state) {
79
+ const { jobIndex, completedJobs, depCompletions, batchIds, missingDependencies } = state;
37
80
  for (let i = 0; i < jobs.length; i++) {
38
81
  const job = jobs[i];
39
82
  try {
@@ -45,6 +88,9 @@ export function validatePushBatchJobs(jobs, ctx) {
45
88
  const dataError = validateJobData(job.data);
46
89
  if (dataError)
47
90
  return `jobs[${i}]: ${dataError}`;
91
+ const groupError = validateGroupId(job.groupId);
92
+ if (groupError)
93
+ return `jobs[${i}]: ${groupError}`;
48
94
  const optionsError = validateJobOptions({
49
95
  priority: job.priority,
50
96
  delay: job.delay,
@@ -61,12 +107,14 @@ export function validatePushBatchJobs(jobs, ctx) {
61
107
  if (key === job.customId) {
62
108
  return `jobs[${i}]: Job cannot depend on itself: ${key}`;
63
109
  }
64
- const exists = jobIndex.has(depId) ||
65
- completedJobs.has(depId) ||
66
- // removeOnComplete parents leave only a bare completion id behind;
67
- // the gate must honor it exactly like PUSH does.
68
- depCompletions.has(depId) ||
69
- (batchIds?.has(key) ?? false);
110
+ const exists = missingDependencies
111
+ ? !missingDependencies.has(depId)
112
+ : jobIndex.has(depId) ||
113
+ completedJobs.has(depId) ||
114
+ // removeOnComplete parents leave only a bare completion id behind;
115
+ // the gate must honor it exactly like PUSH does.
116
+ depCompletions.has(depId) ||
117
+ (batchIds?.has(key) ?? false);
70
118
  if (!exists) {
71
119
  return `jobs[${i}]: Dependency job not found: ${key}`;
72
120
  }
@@ -16,7 +16,7 @@ export declare function handleGetState(cmd: Extract<Command, {
16
16
  /** Handle GetResult command */
17
17
  export declare function handleGetResult(cmd: Extract<Command, {
18
18
  cmd: 'GetResult';
19
- }>, ctx: HandlerContext, reqId?: string): Response;
19
+ }>, ctx: HandlerContext, reqId?: string): Promise<Response>;
20
20
  /** Handle GetJobCounts command */
21
21
  export declare function handleGetJobCounts(cmd: Extract<Command, {
22
22
  cmd: 'GetJobCounts';
@@ -6,6 +6,7 @@ import * as resp from '../../../domain/types/response';
6
6
  import { jobId } from '../../../domain/types/job';
7
7
  import { lastFailedReason } from '../../../domain/job/terminal';
8
8
  import { pausedView } from '../../../shared/pausedView';
9
+ import { sanitizeServerError } from '../errors';
9
10
  function jobView(ctx, job, state) {
10
11
  return {
11
12
  ...job,
@@ -29,8 +30,8 @@ export async function handleGetState(cmd, ctx, reqId) {
29
30
  return { ok: true, id: cmd.id, state, reqId };
30
31
  }
31
32
  /** Handle GetResult command */
32
- export function handleGetResult(cmd, ctx, reqId) {
33
- const result = ctx.queueManager.getResult(jobId(cmd.id));
33
+ export async function handleGetResult(cmd, ctx, reqId) {
34
+ const result = await ctx.queueManager.getResultAsync(jobId(cmd.id));
34
35
  return { ok: true, id: cmd.id, result, reqId };
35
36
  }
36
37
  /** Handle GetJobCounts command */
@@ -86,7 +87,7 @@ export async function handleGetChildrenValues(cmd, ctx, reqId) {
86
87
  const values = await ctx.queueManager.getChildrenValues(jobId(cmd.id));
87
88
  return resp.data({ values }, reqId);
88
89
  }
89
- catch {
90
- return resp.data({ values: {} }, reqId);
90
+ catch (error) {
91
+ return resp.error(sanitizeServerError(error), reqId);
91
92
  }
92
93
  }
@@ -10,6 +10,7 @@ import { WsHandler } from './wsHandler';
10
10
  import { jsonResponse, corsResponse, healthEndpoint, readinessEndpoint, gcEndpoint, heapStatsEndpoint, } from './httpEndpoints';
11
11
  import { loadTlsOptions } from './tls';
12
12
  import { routeHttpRequest } from './httpRouter';
13
+ import { sanitizeServerError } from './errors';
13
14
  /**
14
15
  * Validate auth token against valid tokens set
15
16
  */
@@ -161,8 +162,7 @@ export function createHttpServer(queueManager, config) {
161
162
  return await routeHttpRequest(req, path, ctx, corsOrigins);
162
163
  }
163
164
  catch (err) {
164
- const message = err instanceof Error ? err.message : 'Internal error';
165
- return jsonResponse({ ok: false, error: message }, 500);
165
+ return jsonResponse({ ok: false, error: sanitizeServerError(err) }, 500);
166
166
  }
167
167
  };
168
168
  // WebSocket handlers
@@ -3,7 +3,7 @@
3
3
  */
4
4
  import type { QueueManager } from '../../application/queueManager';
5
5
  /** Dashboard overview endpoint - aggregates all dashboard data in a single call */
6
- export declare function dashboardOverviewEndpoint(queueManager: QueueManager, corsOrigins?: Set<string>): Response;
6
+ export declare function dashboardOverviewEndpoint(queueManager: QueueManager, corsOrigins?: Set<string>): Response | Promise<Response>;
7
7
  /** Dashboard queues endpoint - paginated queues with per-queue stats */
8
8
  export declare function dashboardQueuesEndpoint(queueManager: QueueManager, limit: number, offset: number, corsOrigins?: Set<string>): Response;
9
9
  /** Dashboard single queue detail endpoint */
@@ -4,18 +4,31 @@
4
4
  import { latencyTracker } from '../../application/latencyTracker';
5
5
  import { throughputTracker } from '../../application/throughputTracker';
6
6
  import { pausedView } from '../../shared/pausedView';
7
+ import { clientStorageStatus } from '../../shared/storageHealth';
7
8
  import { jsonResponse } from './httpResponse';
9
+ const WORKER_TIMEOUT_MS = parseInt(Bun.env.WORKER_TIMEOUT_MS ?? '30000', 10);
8
10
  /** Dashboard overview endpoint - aggregates all dashboard data in a single call */
9
11
  export function dashboardOverviewEndpoint(queueManager, corsOrigins) {
12
+ const manager = queueManager;
13
+ if (manager.listWorkersDurable || manager.listCronsDurable) {
14
+ return Promise.all([
15
+ manager.listWorkersDurable
16
+ ? manager.listWorkersDurable()
17
+ : Promise.resolve(manager.workerManager.list()),
18
+ manager.listCronsDurable ? manager.listCronsDurable() : Promise.resolve(manager.listCrons()),
19
+ ]).then(([workers, crons]) => dashboardOverviewResponse(manager, workers, crons, corsOrigins));
20
+ }
21
+ return dashboardOverviewResponse(manager, manager.workerManager.list(), manager.listCrons(), corsOrigins);
22
+ }
23
+ function dashboardOverviewResponse(queueManager, workers, crons, corsOrigins) {
10
24
  const stats = queueManager.getStats();
11
25
  const rates = throughputTracker.getRates();
12
26
  const latencies = latencyTracker.getPercentiles();
13
27
  const avgLatencies = latencyTracker.getAverages();
14
28
  const memStats = queueManager.getMemoryStats();
15
- const workers = queueManager.workerManager.list();
16
- const workerStats = queueManager.workerManager.getStats();
17
- const crons = queueManager.listCrons();
18
- const storage = queueManager.getStorageStatus();
29
+ const now = Date.now();
30
+ const activeWorkers = workers.filter((worker) => now - worker.lastSeen < WORKER_TIMEOUT_MS);
31
+ const storage = clientStorageStatus(queueManager.getStorageStatus());
19
32
  const mem = process.memoryUsage();
20
33
  return jsonResponse({
21
34
  ok: true,
@@ -43,8 +56,8 @@ export function dashboardOverviewEndpoint(queueManager, corsOrigins) {
43
56
  },
44
57
  collections: memStats,
45
58
  workers: {
46
- total: workerStats.total,
47
- active: workerStats.active,
59
+ total: workers.length,
60
+ active: activeWorkers.length,
48
61
  list: workers
49
62
  .slice(0, 100)
50
63
  .map((w) => ({
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * HTTP Endpoints - Health, diagnostics, and stats endpoints
3
3
  */
4
+ import { clientStorageStatus, isStorageDegraded } from '../../shared/storageHealth';
4
5
  import { VERSION } from '../../shared/version';
5
6
  import { throughputTracker } from '../../application/throughputTracker';
6
7
  import { jsonResponse } from './httpResponse';
@@ -39,7 +40,8 @@ export function healthEndpoint(queueManager, wsCount, sseCount, tcpCount = 0) {
39
40
  const uptime = process.uptime();
40
41
  const memoryUsage = process.memoryUsage();
41
42
  const storageStatus = queueManager.getStorageStatus();
42
- const isHealthy = !storageStatus.diskFull;
43
+ const clientStorage = clientStorageStatus(storageStatus);
44
+ const isHealthy = !isStorageDegraded(storageStatus);
43
45
  return jsonResponse({
44
46
  ok: isHealthy,
45
47
  status: isHealthy ? 'healthy' : 'degraded',
@@ -62,11 +64,11 @@ export function healthEndpoint(queueManager, wsCount, sseCount, tcpCount = 0) {
62
64
  heapTotal: Math.round(memoryUsage.heapTotal / 1024 / 1024),
63
65
  rss: Math.round(memoryUsage.rss / 1024 / 1024),
64
66
  },
65
- ...(storageStatus.diskFull && {
67
+ ...(!isHealthy && {
66
68
  storage: {
67
- diskFull: true,
68
- error: storageStatus.error,
69
- since: storageStatus.since,
69
+ diskFull: clientStorage.diskFull,
70
+ error: clientStorage.error,
71
+ since: clientStorage.since,
70
72
  },
71
73
  }),
72
74
  }, isHealthy ? 200 : 503);
@@ -74,11 +76,20 @@ export function healthEndpoint(queueManager, wsCount, sseCount, tcpCount = 0) {
74
76
  /** Readiness check - persistence failures must stop new traffic. */
75
77
  export function readinessEndpoint(queueManager, corsOrigins) {
76
78
  const storage = queueManager.getStorageStatus();
77
- const ready = !storage.diskFull;
79
+ const clientStorage = clientStorageStatus(storage);
80
+ const ready = !isStorageDegraded(storage);
78
81
  return jsonResponse({
79
82
  ok: ready,
80
83
  ready,
81
- ...(ready ? {} : { storage: { diskFull: true, error: storage.error, since: storage.since } }),
84
+ ...(ready
85
+ ? {}
86
+ : {
87
+ storage: {
88
+ diskFull: clientStorage.diskFull,
89
+ error: clientStorage.error,
90
+ since: clientStorage.since,
91
+ },
92
+ }),
82
93
  }, ready ? 200 : 503, corsOrigins);
83
94
  }
84
95
  /** GC endpoint - force garbage collection */
@@ -13,6 +13,7 @@ const RE_QUEUE_CLEAN = /^\/queues\/([^/]+)\/clean$/;
13
13
  const RE_QUEUE_PROMOTE_JOBS = /^\/queues\/([^/]+)\/promote-jobs$/;
14
14
  const RE_QUEUE_RETRY_COMPLETED = /^\/queues\/([^/]+)\/retry-completed$/;
15
15
  const RE_QUEUE_WORKERS = /^\/queues\/([^/]+)\/workers$/;
16
+ const WORKER_TIMEOUT_MS = parseInt(Bun.env.WORKER_TIMEOUT_MS ?? '30000', 10);
16
17
  export async function routeQueueRoutes(request, path, method, context, cors) {
17
18
  if (path === '/queues' && method === 'GET') {
18
19
  return jsonResponse(await handleCommand({ cmd: 'ListQueues' }, context), 200, cors);
@@ -26,7 +27,16 @@ export async function routeQueueRoutes(request, path, method, context, cors) {
26
27
  const queueWorkersMatch = path.match(RE_QUEUE_WORKERS);
27
28
  if (queueWorkersMatch && method === 'GET') {
28
29
  const queue = decodeURIComponent(queueWorkersMatch[1]);
29
- const workers = context.queueManager.workerManager.getForQueue(queue);
30
+ const manager = context.queueManager;
31
+ let workers;
32
+ if (manager.listWorkersDurable) {
33
+ const durableWorkers = await manager.listWorkersDurable();
34
+ const now = Date.now();
35
+ workers = durableWorkers.filter((worker) => worker.queues.includes(queue) && now - worker.lastSeen < WORKER_TIMEOUT_MS);
36
+ }
37
+ else {
38
+ workers = manager.workerManager.getForQueue(queue);
39
+ }
30
40
  return jsonResponse({
31
41
  ok: true,
32
42
  workers: workers.map((worker) => ({
@@ -1,4 +1,5 @@
1
1
  export declare function validateQueueName(name: string): string | null;
2
+ export { validateGroupId } from '../../../domain/types/group';
2
3
  export declare function validateJobData(data: unknown): string | null;
3
4
  export declare function validateNumericField(value: unknown, name: string, options?: {
4
5
  min?: number;
@@ -7,6 +7,7 @@ export function validateQueueName(name) {
7
7
  return 'Queue name contains invalid characters';
8
8
  return null;
9
9
  }
10
+ export { validateGroupId } from '../../../domain/types/group';
10
11
  export function validateJobData(data) {
11
12
  let json;
12
13
  try {
@@ -1,6 +1,6 @@
1
1
  export { createConnectionState, errorResponse, parseCommand, parseCommands, serializeResponse, } from './protocol/commands';
2
2
  export { FrameParser, FrameSizeError, MAX_FRAME_SIZE } from './protocol/frameParser';
3
3
  export { LineBuffer } from './protocol/lineBuffer';
4
- export { validateBackoffField, validateJobData, validateJobOptions, validateNumericField, validateQueueName, } from './protocol/validation';
4
+ export { validateBackoffField, validateGroupId, validateJobData, validateJobOptions, validateNumericField, validateQueueName, } from './protocol/validation';
5
5
  export type { ConnectionState } from './types/protocol';
6
6
  export { validateWebhookUrl } from '../../shared/webhookValidation';
@@ -1,5 +1,5 @@
1
1
  export { createConnectionState, errorResponse, parseCommand, parseCommands, serializeResponse, } from './protocol/commands';
2
2
  export { FrameParser, FrameSizeError, MAX_FRAME_SIZE } from './protocol/frameParser';
3
3
  export { LineBuffer } from './protocol/lineBuffer';
4
- export { validateBackoffField, validateJobData, validateJobOptions, validateNumericField, validateQueueName, } from './protocol/validation';
4
+ export { validateBackoffField, validateGroupId, validateJobData, validateJobOptions, validateNumericField, validateQueueName, } from './protocol/validation';
5
5
  export { validateWebhookUrl } from '../../shared/webhookValidation';
@@ -0,0 +1,24 @@
1
+ export interface ServerShutdownResources {
2
+ readonly shutdownTimeoutMs: number;
3
+ readonly stopStats: () => void;
4
+ readonly stopTcp: () => void;
5
+ readonly stopHttp: () => void;
6
+ readonly getActiveJobs: () => number;
7
+ readonly stopBackup?: () => void;
8
+ readonly emitShutdown: (signal: string) => void;
9
+ readonly stopCloud?: () => Promise<void>;
10
+ readonly shutdownStorage: () => Promise<void>;
11
+ }
12
+ export interface ServerShutdownRuntime {
13
+ readonly now: () => number;
14
+ readonly sleep: (ms: number) => Promise<void>;
15
+ readonly stopRateLimiter: () => void;
16
+ readonly exit: (code: number) => void;
17
+ readonly info: (message: string, data?: Record<string, unknown>) => void;
18
+ readonly warn: (message: string, data?: Record<string, unknown>) => void;
19
+ readonly error: (message: string, data?: Record<string, unknown>) => void;
20
+ readonly cloudTimeoutMs: number;
21
+ readonly storageAttemptTimeoutMs: number;
22
+ }
23
+ /** Memoize the first shutdown so duplicate signals share one total cleanup task. */
24
+ export declare function createServerShutdown(resources: ServerShutdownResources, overrides?: Partial<ServerShutdownRuntime>): (signal: string) => Promise<void>;
@@ -0,0 +1,106 @@
1
+ import { serverLog } from '../../shared/logger';
2
+ import { stopRateLimiter } from './rateLimiter';
3
+ const DEFAULT_RUNTIME = {
4
+ now: Date.now,
5
+ sleep: Bun.sleep,
6
+ stopRateLimiter,
7
+ exit: (code) => process.exit(code),
8
+ info: (message, data) => serverLog.info(message, data),
9
+ warn: (message, data) => serverLog.warn(message, data),
10
+ error: (message, data) => serverLog.error(message, data),
11
+ cloudTimeoutMs: 2_500,
12
+ storageAttemptTimeoutMs: 5_000,
13
+ };
14
+ function errorData(error) {
15
+ return { error: error instanceof Error ? error.message : String(error) };
16
+ }
17
+ async function withTimeout(operation, timeoutMs, label) {
18
+ let timer;
19
+ const timeout = new Promise((_, reject) => {
20
+ timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
21
+ });
22
+ try {
23
+ await Promise.race([Promise.resolve().then(operation), timeout]);
24
+ }
25
+ finally {
26
+ if (timer)
27
+ clearTimeout(timer);
28
+ }
29
+ }
30
+ async function bestEffort(label, operation, runtime) {
31
+ try {
32
+ await operation();
33
+ }
34
+ catch (error) {
35
+ runtime.warn(`${label} failed during shutdown`, errorData(error));
36
+ }
37
+ }
38
+ async function drainActiveJobs(resources, runtime) {
39
+ const startedAt = runtime.now();
40
+ while (runtime.now() - startedAt < resources.shutdownTimeoutMs) {
41
+ let active;
42
+ try {
43
+ active = resources.getActiveJobs();
44
+ }
45
+ catch (error) {
46
+ runtime.warn('Active-job inspection failed during shutdown', errorData(error));
47
+ return;
48
+ }
49
+ if (active === 0)
50
+ return;
51
+ runtime.info(`Waiting for ${active} active jobs...`);
52
+ await runtime.sleep(1_000);
53
+ }
54
+ }
55
+ async function shutdownStorage(resources, runtime) {
56
+ for (let attempt = 1; attempt <= 2; attempt++) {
57
+ try {
58
+ await withTimeout(resources.shutdownStorage, runtime.storageAttemptTimeoutMs, `Storage shutdown attempt ${attempt}`);
59
+ return true;
60
+ }
61
+ catch (error) {
62
+ if (attempt === 1) {
63
+ runtime.warn('Storage shutdown failed; retrying once', errorData(error));
64
+ }
65
+ else {
66
+ runtime.error('Storage shutdown failed after retry', errorData(error));
67
+ }
68
+ }
69
+ }
70
+ return false;
71
+ }
72
+ async function performShutdown(signal, resources, runtime) {
73
+ let exitCode = 0;
74
+ runtime.info(`Received ${signal}, shutting down...`);
75
+ try {
76
+ await bestEffort('Statistics timer cleanup', resources.stopStats, runtime);
77
+ await bestEffort('Rate limiter cleanup', runtime.stopRateLimiter, runtime);
78
+ await bestEffort('TCP server stop', resources.stopTcp, runtime);
79
+ await bestEffort('HTTP server stop', resources.stopHttp, runtime);
80
+ if (resources.stopBackup) {
81
+ await bestEffort('Backup manager stop', resources.stopBackup, runtime);
82
+ }
83
+ await bestEffort('Active-job drain', () => drainActiveJobs(resources, runtime), runtime);
84
+ await bestEffort('Shutdown event emission', () => resources.emitShutdown(signal), runtime);
85
+ const stopCloud = resources.stopCloud;
86
+ if (stopCloud) {
87
+ await bestEffort('Cloud agent stop', () => withTimeout(stopCloud, runtime.cloudTimeoutMs, 'Cloud agent stop'), runtime);
88
+ }
89
+ if (!(await shutdownStorage(resources, runtime)))
90
+ exitCode = 1;
91
+ }
92
+ catch (error) {
93
+ exitCode = 1;
94
+ runtime.error('Unexpected shutdown coordinator failure', errorData(error));
95
+ }
96
+ finally {
97
+ runtime.info(exitCode === 0 ? 'Shutdown complete' : 'Shutdown completed with errors');
98
+ runtime.exit(exitCode);
99
+ }
100
+ }
101
+ /** Memoize the first shutdown so duplicate signals share one total cleanup task. */
102
+ export function createServerShutdown(resources, overrides = {}) {
103
+ const runtime = { ...DEFAULT_RUNTIME, ...overrides };
104
+ let task = null;
105
+ return (signal) => (task ??= performShutdown(signal, resources, runtime));
106
+ }
@@ -54,7 +54,7 @@ export class SseHandler {
54
54
  }, SSE_HEARTBEAT_MS);
55
55
  this.statsInterval ??= setInterval(() => {
56
56
  if (this.clients.size > 0)
57
- this.broadcastStats(qm);
57
+ void this.broadcastStats(qm);
58
58
  }, 5000);
59
59
  this.healthInterval ??= setInterval(() => {
60
60
  if (this.clients.size > 0)
@@ -180,8 +180,13 @@ export class SseHandler {
180
180
  this.clients.delete(clientId);
181
181
  }
182
182
  // ── Periodic broadcasts ────────────────────────────────────
183
- broadcastStats(qm) {
184
- this.sendTypedEvent('stats:snapshot', buildStatsSnapshot(qm));
183
+ async broadcastStats(qm) {
184
+ try {
185
+ this.sendTypedEvent('stats:snapshot', await buildStatsSnapshot(qm));
186
+ }
187
+ catch {
188
+ // A failed durable read must not be replaced by a stale local snapshot.
189
+ }
185
190
  }
186
191
  broadcastHealth(qm) {
187
192
  this.sendTypedEvent('health:status', buildHealthSnapshot(qm, this.clients.size, 'sse'));
@@ -0,0 +1,29 @@
1
+ import type { QueueManager } from '../../application/queueManager';
2
+ import type { ResolvedConfig } from '../../config';
3
+ export type StorageDriver = ResolvedConfig['storageDriver'];
4
+ /** Strategy boundary for one server persistence engine. */
5
+ export interface ServerStorageAdapter {
6
+ readonly driver: StorageDriver;
7
+ startupError(config: ResolvedConfig): string | null;
8
+ create(config: ResolvedConfig): Promise<QueueManager>;
9
+ shutdown(manager: QueueManager): Promise<void>;
10
+ display(config: ResolvedConfig): string;
11
+ }
12
+ /** Immutable adapter registry: adding an engine does not change server bootstrap. */
13
+ export declare class StorageAdapterRegistry {
14
+ private readonly adapters;
15
+ constructor(adapters: readonly ServerStorageAdapter[]);
16
+ resolve(driver: StorageDriver): ServerStorageAdapter;
17
+ drivers(): StorageDriver[];
18
+ }
19
+ /** Lifecycle facade that remembers which strategy owns each created manager. */
20
+ export declare class ServerStorageManager {
21
+ private readonly registry;
22
+ private readonly owners;
23
+ private readonly shutdowns;
24
+ constructor(registry: StorageAdapterRegistry);
25
+ startupError(config: ResolvedConfig): string | null;
26
+ create(config: ResolvedConfig): Promise<QueueManager>;
27
+ shutdown(manager: QueueManager): Promise<boolean>;
28
+ display(config: ResolvedConfig): string;
29
+ }