bunqueue 2.8.60 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (324) hide show
  1. package/README.md +108 -76
  2. package/dist/application/background/dlq.js +2 -0
  3. package/dist/application/contextFactory.js +5 -0
  4. package/dist/application/dlqManager.d.ts +10 -0
  5. package/dist/application/dlqManager.js +47 -9
  6. package/dist/application/dlqRetry.js +59 -38
  7. package/dist/application/eventsManager.d.ts +1 -1
  8. package/dist/application/eventsManager.js +30 -26
  9. package/dist/application/operations/jobManagement.d.ts +4 -0
  10. package/dist/application/operations/jobMoveOperations.js +9 -4
  11. package/dist/application/postgres-queue-manager/batchSnapshot.d.ts +16 -0
  12. package/dist/application/postgres-queue-manager/batchSnapshot.js +17 -0
  13. package/dist/application/postgres-queue-manager/cloud.d.ts +30 -0
  14. package/dist/application/postgres-queue-manager/cloud.js +55 -0
  15. package/dist/application/postgres-queue-manager/config.d.ts +5 -0
  16. package/dist/application/postgres-queue-manager/config.js +1 -0
  17. package/dist/application/postgres-queue-manager/control.d.ts +26 -0
  18. package/dist/application/postgres-queue-manager/control.js +186 -0
  19. package/dist/application/postgres-queue-manager/deferredWrites.d.ts +13 -0
  20. package/dist/application/postgres-queue-manager/deferredWrites.js +60 -0
  21. package/dist/application/postgres-queue-manager/delivery.d.ts +19 -0
  22. package/dist/application/postgres-queue-manager/delivery.js +80 -0
  23. package/dist/application/postgres-queue-manager/lease.d.ts +13 -0
  24. package/dist/application/postgres-queue-manager/lease.js +88 -0
  25. package/dist/application/postgres-queue-manager/lifetimeMetrics.d.ts +32 -0
  26. package/dist/application/postgres-queue-manager/lifetimeMetrics.js +53 -0
  27. package/dist/application/postgres-queue-manager/maintenance.d.ts +14 -0
  28. package/dist/application/postgres-queue-manager/maintenance.js +100 -0
  29. package/dist/application/postgres-queue-manager/operationGate.d.ts +26 -0
  30. package/dist/application/postgres-queue-manager/operationGate.js +96 -0
  31. package/dist/application/postgres-queue-manager/operations.d.ts +25 -0
  32. package/dist/application/postgres-queue-manager/operations.js +194 -0
  33. package/dist/application/postgres-queue-manager/projectionRefreshes.d.ts +43 -0
  34. package/dist/application/postgres-queue-manager/projectionRefreshes.js +170 -0
  35. package/dist/application/postgres-queue-manager/queries.d.ts +142 -0
  36. package/dist/application/postgres-queue-manager/queries.js +231 -0
  37. package/dist/application/postgres-queue-manager/relationships.d.ts +10 -0
  38. package/dist/application/postgres-queue-manager/relationships.js +45 -0
  39. package/dist/application/postgres-queue-manager/services.d.ts +31 -0
  40. package/dist/application/postgres-queue-manager/services.js +149 -0
  41. package/dist/application/postgres-queue-manager/snapshot.d.ts +51 -0
  42. package/dist/application/postgres-queue-manager/snapshot.js +236 -0
  43. package/dist/application/postgres-queue-manager/snapshotViews.d.ts +15 -0
  44. package/dist/application/postgres-queue-manager/snapshotViews.js +100 -0
  45. package/dist/application/postgres-queue-manager/startupEventBuffer.d.ts +12 -0
  46. package/dist/application/postgres-queue-manager/startupEventBuffer.js +36 -0
  47. package/dist/application/postgres-queue-manager/state.d.ts +47 -0
  48. package/dist/application/postgres-queue-manager/state.js +273 -0
  49. package/dist/application/postgres-queue-manager/terminalDelivery.d.ts +20 -0
  50. package/dist/application/postgres-queue-manager/terminalDelivery.js +100 -0
  51. package/dist/application/postgresQueueManager.d.ts +2 -0
  52. package/dist/application/postgresQueueManager.js +1 -0
  53. package/dist/application/queue-manager/flow-failures.js +4 -0
  54. package/dist/application/queue-manager/limits.d.ts +2 -0
  55. package/dist/application/queue-manager/limits.js +4 -0
  56. package/dist/application/queue-manager/observability.js +15 -3
  57. package/dist/application/queue-manager/queries.d.ts +7 -0
  58. package/dist/application/queue-manager/queries.js +9 -0
  59. package/dist/application/queue-manager/services.d.ts +1 -1
  60. package/dist/application/queue-manager/services.js +4 -2
  61. package/dist/application/queue-manager/state.js +16 -1
  62. package/dist/cli/commands/server.js +1 -1
  63. package/dist/client/forwarder.d.ts +6 -4
  64. package/dist/client/forwarder.js +5 -3
  65. package/dist/client/queue/dlq.d.ts +2 -0
  66. package/dist/client/queue/dlq.js +14 -0
  67. package/dist/client/queue/dlqOps.d.ts +2 -0
  68. package/dist/client/queue/dlqOps.js +4 -0
  69. package/dist/client/queue/helpers.js +2 -0
  70. package/dist/client/queue/runtime/configuration.d.ts +4 -0
  71. package/dist/client/queue/runtime/configuration.js +8 -0
  72. package/dist/client/worker/runtime/execution.js +3 -8
  73. package/dist/client/worker/runtime/polling.d.ts +1 -0
  74. package/dist/client/worker/runtime/polling.js +9 -0
  75. package/dist/config/resolve.d.ts +14 -0
  76. package/dist/config/resolve.js +50 -5
  77. package/dist/config/types.d.ts +18 -0
  78. package/dist/domain/queue/dlqShard.d.ts +2 -0
  79. package/dist/domain/queue/dlqShard.js +16 -0
  80. package/dist/domain/queue/shard/dlq.d.ts +1 -0
  81. package/dist/domain/queue/shard/dlq.js +3 -0
  82. package/dist/domain/types/commands/dlq.d.ts +5 -0
  83. package/dist/domain/types/commands/union.d.ts +1 -1
  84. package/dist/domain/types/cron.d.ts +5 -0
  85. package/dist/domain/types/cron.js +14 -3
  86. package/dist/domain/types/dlq.d.ts +1 -1
  87. package/dist/domain/types/dlq.js +1 -2
  88. package/dist/domain/types/jobs/model.d.ts +1 -1
  89. package/dist/infrastructure/cloud/commandHandler.js +5 -3
  90. package/dist/infrastructure/cloud/commands/integrations.js +11 -11
  91. package/dist/infrastructure/cloud/commands/jobs.js +48 -40
  92. package/dist/infrastructure/cloud/commands/queues.js +61 -75
  93. package/dist/infrastructure/cloud/queueAdapter/local.d.ts +41 -0
  94. package/dist/infrastructure/cloud/queueAdapter/local.js +187 -0
  95. package/dist/infrastructure/cloud/queueAdapter/postgres.d.ts +42 -0
  96. package/dist/infrastructure/cloud/queueAdapter/postgres.js +188 -0
  97. package/dist/infrastructure/cloud/queueAdapter/registry.d.ts +4 -0
  98. package/dist/infrastructure/cloud/queueAdapter/registry.js +15 -0
  99. package/dist/infrastructure/cloud/queueAdapter/types.d.ts +87 -0
  100. package/dist/infrastructure/cloud/queueAdapter/types.js +1 -0
  101. package/dist/infrastructure/cloud/snapshot/analytics.d.ts +2 -0
  102. package/dist/infrastructure/cloud/snapshot/analytics.js +7 -0
  103. package/dist/infrastructure/cloud/snapshot/collector.d.ts +4 -0
  104. package/dist/infrastructure/cloud/snapshot/collector.js +39 -1
  105. package/dist/infrastructure/cloud/snapshot/config.d.ts +3 -0
  106. package/dist/infrastructure/cloud/snapshot/config.js +43 -0
  107. package/dist/infrastructure/cloud/snapshot/jobs.d.ts +3 -0
  108. package/dist/infrastructure/cloud/snapshot/jobs.js +32 -1
  109. package/dist/infrastructure/cloud/snapshotCollector.js +20 -35
  110. package/dist/infrastructure/cloud/snapshotHelpers.d.ts +3 -3
  111. package/dist/infrastructure/cloud/snapshotHelpers.js +3 -3
  112. package/dist/infrastructure/cloud/statsRefresh.js +2 -1
  113. package/dist/infrastructure/cloud/types/command.d.ts +2 -2
  114. package/dist/infrastructure/persistence/postgres/admission.d.ts +18 -0
  115. package/dist/infrastructure/persistence/postgres/admission.js +193 -0
  116. package/dist/infrastructure/persistence/postgres/admissionParent.d.ts +5 -0
  117. package/dist/infrastructure/persistence/postgres/admissionParent.js +35 -0
  118. package/dist/infrastructure/persistence/postgres/admissionResult.d.ts +9 -0
  119. package/dist/infrastructure/persistence/postgres/admissionResult.js +1 -0
  120. package/dist/infrastructure/persistence/postgres/admissionStore.d.ts +12 -0
  121. package/dist/infrastructure/persistence/postgres/admissionStore.js +101 -0
  122. package/dist/infrastructure/persistence/postgres/advisoryLocks.d.ts +2 -0
  123. package/dist/infrastructure/persistence/postgres/advisoryLocks.js +13 -0
  124. package/dist/infrastructure/persistence/postgres/batchAdmission.d.ts +11 -0
  125. package/dist/infrastructure/persistence/postgres/batchAdmission.js +110 -0
  126. package/dist/infrastructure/persistence/postgres/batchCompletion.d.ts +4 -0
  127. package/dist/infrastructure/persistence/postgres/batchCompletion.js +174 -0
  128. package/dist/infrastructure/persistence/postgres/batchEvents.d.ts +14 -0
  129. package/dist/infrastructure/persistence/postgres/batchEvents.js +72 -0
  130. package/dist/infrastructure/persistence/postgres/brokerSessions.d.ts +14 -0
  131. package/dist/infrastructure/persistence/postgres/brokerSessions.js +94 -0
  132. package/dist/infrastructure/persistence/postgres/claimBatch.d.ts +11 -0
  133. package/dist/infrastructure/persistence/postgres/claimBatch.js +56 -0
  134. package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +4 -0
  135. package/dist/infrastructure/persistence/postgres/claimSelection.js +198 -0
  136. package/dist/infrastructure/persistence/postgres/claims.d.ts +3 -0
  137. package/dist/infrastructure/persistence/postgres/claims.js +137 -0
  138. package/dist/infrastructure/persistence/postgres/cloudReadModel.d.ts +26 -0
  139. package/dist/infrastructure/persistence/postgres/cloudReadModel.js +123 -0
  140. package/dist/infrastructure/persistence/postgres/codec.d.ts +30 -0
  141. package/dist/infrastructure/persistence/postgres/codec.js +82 -0
  142. package/dist/infrastructure/persistence/postgres/completionEvents.d.ts +11 -0
  143. package/dist/infrastructure/persistence/postgres/completionEvents.js +21 -0
  144. package/dist/infrastructure/persistence/postgres/completionLifecycle.d.ts +11 -0
  145. package/dist/infrastructure/persistence/postgres/completionLifecycle.js +145 -0
  146. package/dist/infrastructure/persistence/postgres/completionOutcome.d.ts +4 -0
  147. package/dist/infrastructure/persistence/postgres/completionOutcome.js +112 -0
  148. package/dist/infrastructure/persistence/postgres/completionQueries.d.ts +10 -0
  149. package/dist/infrastructure/persistence/postgres/completionQueries.js +87 -0
  150. package/dist/infrastructure/persistence/postgres/connection.d.ts +3 -0
  151. package/dist/infrastructure/persistence/postgres/connection.js +15 -0
  152. package/dist/infrastructure/persistence/postgres/context.d.ts +28 -0
  153. package/dist/infrastructure/persistence/postgres/context.js +74 -0
  154. package/dist/infrastructure/persistence/postgres/control.d.ts +23 -0
  155. package/dist/infrastructure/persistence/postgres/control.js +105 -0
  156. package/dist/infrastructure/persistence/postgres/crons.d.ts +18 -0
  157. package/dist/infrastructure/persistence/postgres/crons.js +205 -0
  158. package/dist/infrastructure/persistence/postgres/deduplication.d.ts +9 -0
  159. package/dist/infrastructure/persistence/postgres/deduplication.js +47 -0
  160. package/dist/infrastructure/persistence/postgres/dependencyDestruction.d.ts +14 -0
  161. package/dist/infrastructure/persistence/postgres/dependencyDestruction.js +74 -0
  162. package/dist/infrastructure/persistence/postgres/dependencyPromotion.d.ts +29 -0
  163. package/dist/infrastructure/persistence/postgres/dependencyPromotion.js +212 -0
  164. package/dist/infrastructure/persistence/postgres/destructiveMutations.d.ts +4 -0
  165. package/dist/infrastructure/persistence/postgres/destructiveMutations.js +111 -0
  166. package/dist/infrastructure/persistence/postgres/dlqLifecycle.d.ts +13 -0
  167. package/dist/infrastructure/persistence/postgres/dlqLifecycle.js +184 -0
  168. package/dist/infrastructure/persistence/postgres/dlqMaintenance.d.ts +6 -0
  169. package/dist/infrastructure/persistence/postgres/dlqMaintenance.js +36 -0
  170. package/dist/infrastructure/persistence/postgres/dlqRetryPlan.d.ts +21 -0
  171. package/dist/infrastructure/persistence/postgres/dlqRetryPlan.js +92 -0
  172. package/dist/infrastructure/persistence/postgres/eventCommitGc.d.ts +27 -0
  173. package/dist/infrastructure/persistence/postgres/eventCommitGc.js +62 -0
  174. package/dist/infrastructure/persistence/postgres/eventJournal.d.ts +18 -0
  175. package/dist/infrastructure/persistence/postgres/eventJournal.js +76 -0
  176. package/dist/infrastructure/persistence/postgres/eventJournalSchema.d.ts +5 -0
  177. package/dist/infrastructure/persistence/postgres/eventJournalSchema.js +253 -0
  178. package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +24 -0
  179. package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +111 -0
  180. package/dist/infrastructure/persistence/postgres/eventRetention.d.ts +18 -0
  181. package/dist/infrastructure/persistence/postgres/eventRetention.js +76 -0
  182. package/dist/infrastructure/persistence/postgres/events.d.ts +45 -0
  183. package/dist/infrastructure/persistence/postgres/events.js +249 -0
  184. package/dist/infrastructure/persistence/postgres/expiry.d.ts +3 -0
  185. package/dist/infrastructure/persistence/postgres/expiry.js +74 -0
  186. package/dist/infrastructure/persistence/postgres/flowFailures.d.ts +17 -0
  187. package/dist/infrastructure/persistence/postgres/flowFailures.js +199 -0
  188. package/dist/infrastructure/persistence/postgres/jobData.d.ts +3 -0
  189. package/dist/infrastructure/persistence/postgres/jobData.js +32 -0
  190. package/dist/infrastructure/persistence/postgres/leaseRelease.d.ts +9 -0
  191. package/dist/infrastructure/persistence/postgres/leaseRelease.js +120 -0
  192. package/dist/infrastructure/persistence/postgres/leaseRenewal.d.ts +4 -0
  193. package/dist/infrastructure/persistence/postgres/leaseRenewal.js +35 -0
  194. package/dist/infrastructure/persistence/postgres/lifetimeMetrics.d.ts +15 -0
  195. package/dist/infrastructure/persistence/postgres/lifetimeMetrics.js +46 -0
  196. package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.d.ts +4 -0
  197. package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.js +13 -0
  198. package/dist/infrastructure/persistence/postgres/logs.d.ts +6 -0
  199. package/dist/infrastructure/persistence/postgres/logs.js +70 -0
  200. package/dist/infrastructure/persistence/postgres/maintenance.d.ts +6 -0
  201. package/dist/infrastructure/persistence/postgres/maintenance.js +138 -0
  202. package/dist/infrastructure/persistence/postgres/maintenanceFlights.d.ts +14 -0
  203. package/dist/infrastructure/persistence/postgres/maintenanceFlights.js +66 -0
  204. package/dist/infrastructure/persistence/postgres/metricWrites.d.ts +9 -0
  205. package/dist/infrastructure/persistence/postgres/metricWrites.js +94 -0
  206. package/dist/infrastructure/persistence/postgres/mutations.d.ts +9 -0
  207. package/dist/infrastructure/persistence/postgres/mutations.js +171 -0
  208. package/dist/infrastructure/persistence/postgres/outcomes.d.ts +4 -0
  209. package/dist/infrastructure/persistence/postgres/outcomes.js +194 -0
  210. package/dist/infrastructure/persistence/postgres/policies.d.ts +11 -0
  211. package/dist/infrastructure/persistence/postgres/policies.js +18 -0
  212. package/dist/infrastructure/persistence/postgres/postCommitMaintenance.d.ts +17 -0
  213. package/dist/infrastructure/persistence/postgres/postCommitMaintenance.js +117 -0
  214. package/dist/infrastructure/persistence/postgres/promotion.d.ts +3 -0
  215. package/dist/infrastructure/persistence/postgres/promotion.js +43 -0
  216. package/dist/infrastructure/persistence/postgres/queries.d.ts +22 -0
  217. package/dist/infrastructure/persistence/postgres/queries.js +152 -0
  218. package/dist/infrastructure/persistence/postgres/queueDestruction.d.ts +3 -0
  219. package/dist/infrastructure/persistence/postgres/queueDestruction.js +154 -0
  220. package/dist/infrastructure/persistence/postgres/queueLifecycle.d.ts +10 -0
  221. package/dist/infrastructure/persistence/postgres/queueLifecycle.js +60 -0
  222. package/dist/infrastructure/persistence/postgres/rateLimit.d.ts +6 -0
  223. package/dist/infrastructure/persistence/postgres/rateLimit.js +10 -0
  224. package/dist/infrastructure/persistence/postgres/readModels.d.ts +32 -0
  225. package/dist/infrastructure/persistence/postgres/readModels.js +72 -0
  226. package/dist/infrastructure/persistence/postgres/recovery.d.ts +3 -0
  227. package/dist/infrastructure/persistence/postgres/recovery.js +178 -0
  228. package/dist/infrastructure/persistence/postgres/relationships.d.ts +9 -0
  229. package/dist/infrastructure/persistence/postgres/relationships.js +201 -0
  230. package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.d.ts +4 -0
  231. package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.js +241 -0
  232. package/dist/infrastructure/persistence/postgres/repeatMutations.d.ts +5 -0
  233. package/dist/infrastructure/persistence/postgres/repeatMutations.js +37 -0
  234. package/dist/infrastructure/persistence/postgres/runtime.d.ts +46 -0
  235. package/dist/infrastructure/persistence/postgres/runtime.js +236 -0
  236. package/dist/infrastructure/persistence/postgres/runtimeConfig.d.ts +21 -0
  237. package/dist/infrastructure/persistence/postgres/runtimeConfig.js +39 -0
  238. package/dist/infrastructure/persistence/postgres/schema.d.ts +4 -0
  239. package/dist/infrastructure/persistence/postgres/schema.js +257 -0
  240. package/dist/infrastructure/persistence/postgres/schemaInitialization.d.ts +3 -0
  241. package/dist/infrastructure/persistence/postgres/schemaInitialization.js +221 -0
  242. package/dist/infrastructure/persistence/postgres/serialAdmission.d.ts +6 -0
  243. package/dist/infrastructure/persistence/postgres/serialAdmission.js +96 -0
  244. package/dist/infrastructure/persistence/postgres/snapshotBudget.d.ts +3 -0
  245. package/dist/infrastructure/persistence/postgres/snapshotBudget.js +83 -0
  246. package/dist/infrastructure/persistence/postgres/storageHealth.d.ts +10 -0
  247. package/dist/infrastructure/persistence/postgres/storageHealth.js +29 -0
  248. package/dist/infrastructure/persistence/postgres/store.d.ts +90 -0
  249. package/dist/infrastructure/persistence/postgres/store.js +136 -0
  250. package/dist/infrastructure/persistence/postgres/telemetry.d.ts +6 -0
  251. package/dist/infrastructure/persistence/postgres/telemetry.js +88 -0
  252. package/dist/infrastructure/persistence/postgres/terminal.d.ts +8 -0
  253. package/dist/infrastructure/persistence/postgres/terminal.js +137 -0
  254. package/dist/infrastructure/persistence/postgres/transactionRetry.d.ts +6 -0
  255. package/dist/infrastructure/persistence/postgres/transactionRetry.js +42 -0
  256. package/dist/infrastructure/persistence/postgres/types.d.ts +175 -0
  257. package/dist/infrastructure/persistence/postgres/types.js +1 -0
  258. package/dist/infrastructure/persistence/postgres/workers.d.ts +15 -0
  259. package/dist/infrastructure/persistence/postgres/workers.js +126 -0
  260. package/dist/infrastructure/persistence/postgres.d.ts +2 -0
  261. package/dist/infrastructure/persistence/postgres.js +1 -0
  262. package/dist/infrastructure/persistence/sqlite/jobs.js +2 -0
  263. package/dist/infrastructure/scheduler/cron/persisted.d.ts +5 -0
  264. package/dist/infrastructure/scheduler/cron/persisted.js +27 -0
  265. package/dist/infrastructure/scheduler/cron/runtime.js +5 -10
  266. package/dist/infrastructure/scheduler/cron/validation.d.ts +3 -0
  267. package/dist/infrastructure/scheduler/cron/validation.js +11 -0
  268. package/dist/infrastructure/scheduler/cronParser.d.ts +1 -1
  269. package/dist/infrastructure/scheduler/cronParser.js +144 -11
  270. package/dist/infrastructure/server/bootstrap.d.ts +2 -3
  271. package/dist/infrastructure/server/bootstrap.js +33 -59
  272. package/dist/infrastructure/server/errors.d.ts +4 -0
  273. package/dist/infrastructure/server/errors.js +54 -0
  274. package/dist/infrastructure/server/handler-routes/control.d.ts +5 -5
  275. package/dist/infrastructure/server/handler-routes/control.js +3 -1
  276. package/dist/infrastructure/server/handler-routes/monitoring.d.ts +2 -2
  277. package/dist/infrastructure/server/handler.js +9 -11
  278. package/dist/infrastructure/server/handlers/advanced/dependencies.js +7 -6
  279. package/dist/infrastructure/server/handlers/advanced/jobs.js +19 -6
  280. package/dist/infrastructure/server/handlers/advanced/queue.d.ts +9 -9
  281. package/dist/infrastructure/server/handlers/advanced/queue.js +91 -27
  282. package/dist/infrastructure/server/handlers/core.js +32 -31
  283. package/dist/infrastructure/server/handlers/cron.d.ts +4 -4
  284. package/dist/infrastructure/server/handlers/cron.js +60 -59
  285. package/dist/infrastructure/server/handlers/dashboard.d.ts +1 -1
  286. package/dist/infrastructure/server/handlers/dashboard.js +21 -8
  287. package/dist/infrastructure/server/handlers/dlq.d.ts +6 -3
  288. package/dist/infrastructure/server/handlers/dlq.js +35 -9
  289. package/dist/infrastructure/server/handlers/flow.js +2 -1
  290. package/dist/infrastructure/server/handlers/management.d.ts +5 -5
  291. package/dist/infrastructure/server/handlers/management.js +36 -9
  292. package/dist/infrastructure/server/handlers/monitoring/health.d.ts +5 -5
  293. package/dist/infrastructure/server/handlers/monitoring/health.js +45 -16
  294. package/dist/infrastructure/server/handlers/monitoring/operations.d.ts +1 -1
  295. package/dist/infrastructure/server/handlers/monitoring/operations.js +8 -1
  296. package/dist/infrastructure/server/handlers/monitoring/workers.d.ts +3 -3
  297. package/dist/infrastructure/server/handlers/monitoring/workers.js +31 -7
  298. package/dist/infrastructure/server/handlers/pushBatchValidation.d.ts +3 -1
  299. package/dist/infrastructure/server/handlers/pushBatchValidation.js +52 -7
  300. package/dist/infrastructure/server/handlers/query.d.ts +1 -1
  301. package/dist/infrastructure/server/handlers/query.js +5 -4
  302. package/dist/infrastructure/server/http.js +2 -2
  303. package/dist/infrastructure/server/httpDashboardEndpoints.d.ts +1 -1
  304. package/dist/infrastructure/server/httpDashboardEndpoints.js +19 -6
  305. package/dist/infrastructure/server/httpEndpoints.js +18 -7
  306. package/dist/infrastructure/server/httpRouteQueues.js +11 -1
  307. package/dist/infrastructure/server/shutdownCoordinator.d.ts +24 -0
  308. package/dist/infrastructure/server/shutdownCoordinator.js +106 -0
  309. package/dist/infrastructure/server/sseHandler.js +8 -3
  310. package/dist/infrastructure/server/storageAdapter.d.ts +29 -0
  311. package/dist/infrastructure/server/storageAdapter.js +61 -0
  312. package/dist/infrastructure/server/storageManager.d.ts +12 -0
  313. package/dist/infrastructure/server/storageManager.js +102 -0
  314. package/dist/infrastructure/server/tcp.js +2 -3
  315. package/dist/infrastructure/server/ws/snapshots.d.ts +1 -1
  316. package/dist/infrastructure/server/ws/snapshots.js +19 -4
  317. package/dist/infrastructure/server/wsHandler.js +10 -5
  318. package/dist/main.js +1 -1
  319. package/dist/mcp/backend/embedded/services.js +2 -1
  320. package/dist/mcp/index.d.ts +2 -2
  321. package/dist/mcp/index.js +2 -2
  322. package/dist/shared/storageHealth.d.ts +9 -0
  323. package/dist/shared/storageHealth.js +12 -0
  324. package/package.json +74 -65
@@ -0,0 +1,120 @@
1
+ import { jobId } from '../../../domain/types/job';
2
+ import { decodePostgresJob, encodePostgresValue } from './codec';
3
+ import { databaseNow, recordPostgresEvent } from './context';
4
+ import { lockPostgresDestructionIdentities, partitionPostgresDestructionCandidates, } from './dependencyDestruction';
5
+ import { lockPostgresBrokerSession } from './brokerSessions';
6
+ function isProtectedCron(row) {
7
+ return decodePostgresJob(row).job.uniqueKey?.startsWith('cron:') === true;
8
+ }
9
+ export async function discardPostgresProtectedCronLease(tx, ctx, row, now) {
10
+ if (!isProtectedCron(row))
11
+ return false;
12
+ const id = jobId(row.id);
13
+ const { protectedIds } = await partitionPostgresDestructionCandidates(tx, ctx, [id], [id]);
14
+ if (protectedIds.length > 0)
15
+ return false;
16
+ const job = decodePostgresJob(row).job;
17
+ await tx `
18
+ DELETE FROM bunqueue_job_logs
19
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${row.id}
20
+ `;
21
+ await tx `
22
+ DELETE FROM bunqueue_flow_failures
23
+ WHERE namespace = ${ctx.config.namespace} AND parent_id = ${row.id}
24
+ `;
25
+ await tx `
26
+ DELETE FROM bunqueue_dependencies
27
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${row.id}
28
+ `;
29
+ await tx `
30
+ DELETE FROM bunqueue_jobs
31
+ WHERE namespace = ${ctx.config.namespace} AND id = ${row.id}
32
+ `;
33
+ await recordPostgresEvent(tx, ctx, {
34
+ queue: job.queue,
35
+ type: 'removed',
36
+ jobId: job.id,
37
+ occurredAt: now,
38
+ job,
39
+ state: 'active',
40
+ removed: true,
41
+ });
42
+ return true;
43
+ }
44
+ async function releaseLeaseRow(tx, ctx, row, now) {
45
+ if (await discardPostgresProtectedCronLease(tx, ctx, row, now))
46
+ return;
47
+ const job = decodePostgresJob(row).job;
48
+ job.startedAt = null;
49
+ job.runAt = Math.min(job.runAt, now);
50
+ const state = job.priority > 0 ? 'prioritized' : 'waiting';
51
+ await tx `
52
+ UPDATE bunqueue_jobs
53
+ SET payload = ${encodePostgresValue(job)}, state = ${state}, run_at = ${job.runAt},
54
+ started_at = NULL, lease_owner = NULL, lease_token = NULL, lease_until = NULL,
55
+ lease_broker_id = NULL, lease_broker_session_id = NULL,
56
+ lease_renewals = 0, version = version + 1
57
+ WHERE namespace = ${ctx.config.namespace} AND id = ${row.id}
58
+ `;
59
+ await recordPostgresEvent(tx, ctx, {
60
+ queue: job.queue,
61
+ type: 'retried',
62
+ jobId: job.id,
63
+ occurredAt: now,
64
+ job,
65
+ state,
66
+ });
67
+ }
68
+ /** Release a never-renewed connection lease without racing pooled heartbeats. */
69
+ export async function releasePostgresClientLease(ctx, id, token) {
70
+ return await ctx.sql.begin(async (tx) => {
71
+ await lockPostgresBrokerSession(tx, ctx);
72
+ await lockPostgresDestructionIdentities(tx, ctx, [id]);
73
+ const now = await databaseNow(tx);
74
+ const rows = await tx `
75
+ SELECT * FROM bunqueue_jobs
76
+ WHERE namespace = ${ctx.config.namespace} AND id = ${String(id)}
77
+ FOR UPDATE
78
+ `;
79
+ const row = rows[0];
80
+ if (row?.state !== 'active' ||
81
+ row.lease_token !== token ||
82
+ Number(row.lease_until ?? 0) <= now ||
83
+ row.lease_renewals > 0) {
84
+ return false;
85
+ }
86
+ await releaseLeaseRow(tx, ctx, row, now);
87
+ return true;
88
+ });
89
+ }
90
+ /** Return or discard every active lease currently coordinated by this broker. */
91
+ export async function releasePostgresBrokerLeases(ctx) {
92
+ return await ctx.sql.begin(async (tx) => {
93
+ const now = await databaseNow(tx);
94
+ const candidates = await tx `
95
+ SELECT id FROM bunqueue_jobs
96
+ WHERE namespace = ${ctx.config.namespace}
97
+ AND state = 'active'
98
+ AND lease_broker_id = ${ctx.config.brokerId}
99
+ AND lease_broker_session_id = ${ctx.config.brokerSessionId}
100
+ ORDER BY id
101
+ `;
102
+ const ids = candidates.map((row) => jobId(row.id));
103
+ if (ids.length === 0)
104
+ return 0;
105
+ await lockPostgresDestructionIdentities(tx, ctx, ids);
106
+ const rows = await tx `
107
+ SELECT * FROM bunqueue_jobs
108
+ WHERE namespace = ${ctx.config.namespace}
109
+ AND state = 'active'
110
+ AND lease_broker_id = ${ctx.config.brokerId}
111
+ AND lease_broker_session_id = ${ctx.config.brokerSessionId}
112
+ AND id = ANY(${tx.array(ids.map(String), 'TEXT')})
113
+ ORDER BY id
114
+ FOR UPDATE
115
+ `;
116
+ for (const row of rows)
117
+ await releaseLeaseRow(tx, ctx, row, now);
118
+ return rows.length;
119
+ });
120
+ }
@@ -0,0 +1,4 @@
1
+ import type { JobId } from '../../../domain/types/job';
2
+ import { type PostgresContext } from './context';
3
+ /** Renew one fenced lease and transfer its broker responsibility atomically. */
4
+ export declare function renewPostgresLease(ctx: PostgresContext, id: JobId, token: string, durationMs: number): Promise<number | null>;
@@ -0,0 +1,35 @@
1
+ import { decodePostgresJob, encodePostgresValue } from './codec';
2
+ import { databaseNow } from './context';
3
+ import { lockPostgresBrokerSession } from './brokerSessions';
4
+ /** Renew one fenced lease and transfer its broker responsibility atomically. */
5
+ export async function renewPostgresLease(ctx, id, token, durationMs) {
6
+ return await ctx.sql.begin(async (tx) => {
7
+ await lockPostgresBrokerSession(tx, ctx);
8
+ const now = await databaseNow(tx);
9
+ const rows = await tx `
10
+ SELECT * FROM bunqueue_jobs
11
+ WHERE namespace = ${ctx.config.namespace} AND id = ${String(id)}
12
+ AND state = 'active' AND lease_token = ${token} AND lease_until > ${now}
13
+ FOR UPDATE
14
+ `;
15
+ const row = rows[0];
16
+ if (!row)
17
+ return null;
18
+ const job = decodePostgresJob(row).job;
19
+ job.lastHeartbeat = now;
20
+ const requestedLeaseUntil = now + Math.max(1, durationMs);
21
+ const leaseUntil = row.timeout === null
22
+ ? requestedLeaseUntil
23
+ : Math.min(requestedLeaseUntil, Number(row.started_at ?? now) + Number(row.timeout));
24
+ await tx `
25
+ UPDATE bunqueue_jobs
26
+ SET payload = ${encodePostgresValue(job)}, lease_until = ${leaseUntil},
27
+ lease_broker_id = ${ctx.config.brokerId},
28
+ lease_broker_session_id = ${ctx.config.brokerSessionId},
29
+ lease_renewals = lease_renewals + 1,
30
+ version = version + 1
31
+ WHERE namespace = ${ctx.config.namespace} AND id = ${String(id)}
32
+ `;
33
+ return leaseUntil;
34
+ });
35
+ }
@@ -0,0 +1,15 @@
1
+ import type { PostgresContext, PostgresReadSql } from './context';
2
+ export interface PostgresQueueLifetimeTotals {
3
+ readonly queue: string;
4
+ readonly totalCompleted: bigint;
5
+ readonly totalFailed: bigint;
6
+ }
7
+ export interface PostgresLifetimeMetricsSnapshot {
8
+ readonly baselineEventId: number;
9
+ readonly baselineCommitSeq: number;
10
+ readonly totalCompleted: bigint;
11
+ readonly totalFailed: bigint;
12
+ readonly queues: readonly PostgresQueueLifetimeTotals[];
13
+ }
14
+ /** Load terminal lifetime counters and their matching event boundary atomically. */
15
+ export declare function loadPostgresLifetimeMetrics(ctx: PostgresContext, sql?: PostgresReadSql): Promise<PostgresLifetimeMetricsSnapshot>;
@@ -0,0 +1,46 @@
1
+ /** Load terminal lifetime counters and their matching event boundary atomically. */
2
+ export async function loadPostgresLifetimeMetrics(ctx, sql) {
3
+ const load = async (readSql) => {
4
+ const [[baseline], rows] = await Promise.all([
5
+ readSql `
6
+ SELECT
7
+ (SELECT MAX(id) FROM bunqueue_events
8
+ WHERE namespace = ${ctx.config.namespace}) AS event_id,
9
+ (SELECT MAX(commit_seq) FROM bunqueue_event_commits
10
+ WHERE namespace = ${ctx.config.namespace}) AS commit_seq
11
+ `,
12
+ readSql `
13
+ SELECT queue, metric_type, total_count
14
+ FROM bunqueue_metric_totals
15
+ WHERE namespace = ${ctx.config.namespace}
16
+ ORDER BY queue, metric_type
17
+ `,
18
+ ]);
19
+ const queues = new Map();
20
+ let totalCompleted = 0n;
21
+ let totalFailed = 0n;
22
+ for (const row of rows) {
23
+ const count = BigInt(row.total_count);
24
+ const totals = queues.get(row.queue) ?? { totalCompleted: 0n, totalFailed: 0n };
25
+ if (row.metric_type === 'completed') {
26
+ totals.totalCompleted = count;
27
+ totalCompleted += count;
28
+ }
29
+ else {
30
+ totals.totalFailed = count;
31
+ totalFailed += count;
32
+ }
33
+ queues.set(row.queue, totals);
34
+ }
35
+ return {
36
+ baselineEventId: Number(baseline.event_id ?? 0),
37
+ baselineCommitSeq: Number(baseline.commit_seq ?? 0),
38
+ totalCompleted,
39
+ totalFailed,
40
+ queues: [...queues].map(([queue, totals]) => ({ queue, ...totals })),
41
+ };
42
+ };
43
+ if (sql)
44
+ return await load(sql);
45
+ return await ctx.sql.begin('isolation level repeatable read read only', load);
46
+ }
@@ -0,0 +1,4 @@
1
+ import type { PostgresContext } from './context';
2
+ import { type PostgresLifetimeMetricsSnapshot } from './lifetimeMetrics';
3
+ /** Fence terminal counters against the same commit sequencer used by journal writers. */
4
+ export declare function finalizePostgresLifetimeMetrics(ctx: PostgresContext, apply: (snapshot: PostgresLifetimeMetricsSnapshot) => void): Promise<void>;
@@ -0,0 +1,13 @@
1
+ import { postgresAdvisoryLockName } from './advisoryLocks';
2
+ import { loadPostgresLifetimeMetrics, } from './lifetimeMetrics';
3
+ /** Fence terminal counters against the same commit sequencer used by journal writers. */
4
+ export async function finalizePostgresLifetimeMetrics(ctx, apply) {
5
+ const lockName = postgresAdvisoryLockName('event-commit', ctx.config.namespace);
6
+ await ctx.sql.begin(async (tx) => {
7
+ await tx `
8
+ SELECT pg_advisory_xact_lock(hashtextextended(${lockName}, 0))
9
+ `;
10
+ const snapshot = await loadPostgresLifetimeMetrics(ctx, tx);
11
+ apply(snapshot);
12
+ });
13
+ }
@@ -0,0 +1,6 @@
1
+ import type { JobId } from '../../../domain/types/job';
2
+ import type { JobLogEntry } from '../../../domain/types/worker';
3
+ import { type PostgresContext } from './context';
4
+ export declare function addPostgresJobLog(ctx: PostgresContext, id: JobId, message: string, level: JobLogEntry['level'], maxLogs?: number): Promise<boolean>;
5
+ export declare function getPostgresJobLogs(ctx: PostgresContext, id: JobId): Promise<JobLogEntry[]>;
6
+ export declare function clearPostgresJobLogs(ctx: PostgresContext, id: JobId, keepLogs?: number): Promise<void>;
@@ -0,0 +1,70 @@
1
+ import { databaseNow } from './context';
2
+ export async function addPostgresJobLog(ctx, id, message, level, maxLogs = 100) {
3
+ return await ctx.sql.begin(async (tx) => {
4
+ const jobs = await tx `
5
+ SELECT id FROM bunqueue_jobs
6
+ WHERE namespace = ${ctx.config.namespace} AND id = ${String(id)}
7
+ FOR UPDATE
8
+ `;
9
+ if (!jobs[0])
10
+ return false;
11
+ const now = await databaseNow(tx);
12
+ const rows = await tx `
13
+ INSERT INTO bunqueue_job_logs (namespace, job_id, timestamp, level, message)
14
+ VALUES (${ctx.config.namespace}, ${String(id)}, ${now}, ${level}, ${message})
15
+ RETURNING id
16
+ `;
17
+ if (!rows[0])
18
+ return false;
19
+ await tx `
20
+ DELETE FROM bunqueue_job_logs
21
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(id)}
22
+ AND id NOT IN (
23
+ SELECT id FROM bunqueue_job_logs
24
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(id)}
25
+ ORDER BY id DESC
26
+ LIMIT ${Math.max(1, maxLogs)}
27
+ )
28
+ `;
29
+ return true;
30
+ });
31
+ }
32
+ export async function getPostgresJobLogs(ctx, id) {
33
+ const rows = await ctx.sql `
34
+ SELECT timestamp, level, message
35
+ FROM bunqueue_job_logs
36
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(id)}
37
+ ORDER BY id
38
+ `;
39
+ return rows.map((row) => ({
40
+ timestamp: Number(row.timestamp),
41
+ level: row.level,
42
+ message: row.message,
43
+ }));
44
+ }
45
+ export async function clearPostgresJobLogs(ctx, id, keepLogs) {
46
+ await ctx.sql.begin(async (tx) => {
47
+ await tx `
48
+ SELECT id FROM bunqueue_jobs
49
+ WHERE namespace = ${ctx.config.namespace} AND id = ${String(id)}
50
+ FOR UPDATE
51
+ `;
52
+ if (keepLogs === undefined || keepLogs <= 0) {
53
+ await tx `
54
+ DELETE FROM bunqueue_job_logs
55
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(id)}
56
+ `;
57
+ return;
58
+ }
59
+ await tx `
60
+ DELETE FROM bunqueue_job_logs
61
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(id)}
62
+ AND id NOT IN (
63
+ SELECT id FROM bunqueue_job_logs
64
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(id)}
65
+ ORDER BY id DESC
66
+ LIMIT ${Math.floor(keepLogs)}
67
+ )
68
+ `;
69
+ });
70
+ }
@@ -0,0 +1,6 @@
1
+ import { type JobId } from '../../../domain/types/job';
2
+ import { type PostgresContext } from './context';
3
+ /** Remove old jobs with the same state grouping used by Queue.clean(). */
4
+ export declare function cleanPostgresQueue(ctx: PostgresContext, queue: string, graceMs: number, state?: string, limit?: number): Promise<JobId[]>;
5
+ /** Permanently remove every failed job currently visible in one queue. */
6
+ export declare function purgePostgresDlq(ctx: PostgresContext, queue: string): Promise<JobId[]>;
@@ -0,0 +1,138 @@
1
+ import { jobId } from '../../../domain/types/job';
2
+ import { decodePostgresJob } from './codec';
3
+ import { databaseNow, recordPostgresEvent } from './context';
4
+ import { lockPostgresDestructionCandidates, partitionPostgresDestructionCandidates, } from './dependencyDestruction';
5
+ async function prepareDeletableRows(tx, ctx, candidateIds, load) {
6
+ if (candidateIds.length === 0)
7
+ return [];
8
+ await lockPostgresDestructionCandidates(tx, ctx, candidateIds);
9
+ const rows = await load(candidateIds);
10
+ const plannedIds = rows.map((row) => jobId(row.id));
11
+ const { deletableIds } = await partitionPostgresDestructionCandidates(tx, ctx, plannedIds, plannedIds);
12
+ const deletable = new Set(deletableIds.map(String));
13
+ return rows.filter((row) => deletable.has(row.id));
14
+ }
15
+ async function deleteRows(tx, ctx, rows) {
16
+ if (rows.length === 0)
17
+ return [];
18
+ const ids = rows.map((row) => row.id);
19
+ await tx `
20
+ DELETE FROM bunqueue_job_logs
21
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${tx.array(ids, 'TEXT')})
22
+ `;
23
+ await tx `
24
+ DELETE FROM bunqueue_flow_failures
25
+ WHERE namespace = ${ctx.config.namespace}
26
+ AND parent_id = ANY(${tx.array(ids, 'TEXT')})
27
+ `;
28
+ await tx `
29
+ DELETE FROM bunqueue_dependencies
30
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${tx.array(ids, 'TEXT')})
31
+ `;
32
+ await tx `
33
+ DELETE FROM bunqueue_completions
34
+ WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${tx.array(ids, 'TEXT')})
35
+ `;
36
+ await tx `
37
+ DELETE FROM bunqueue_jobs
38
+ WHERE namespace = ${ctx.config.namespace} AND id = ANY(${tx.array(ids, 'TEXT')})
39
+ `;
40
+ const now = await databaseNow(tx);
41
+ for (const row of rows) {
42
+ const job = decodePostgresJob(row).job;
43
+ await recordPostgresEvent(tx, ctx, {
44
+ queue: job.queue,
45
+ type: 'removed',
46
+ jobId: job.id,
47
+ occurredAt: now,
48
+ job,
49
+ state: row.state,
50
+ removed: true,
51
+ });
52
+ }
53
+ return ids.map(jobId);
54
+ }
55
+ /** Remove old jobs with the same state grouping used by Queue.clean(). */
56
+ export async function cleanPostgresQueue(ctx, queue, graceMs, state, limit = 1000) {
57
+ const cap = Number.isFinite(limit) && limit > 0 ? Math.floor(limit) : 0;
58
+ if (cap === 0 || state === 'active')
59
+ return [];
60
+ return await ctx.sql.begin(async (tx) => {
61
+ const threshold = (await databaseNow(tx)) - graceMs;
62
+ let rows;
63
+ if (state === 'completed') {
64
+ const candidates = await tx `
65
+ SELECT id FROM bunqueue_jobs
66
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
67
+ AND state = 'completed' AND COALESCE(completed_at, created_at) <= ${threshold}
68
+ ORDER BY COALESCE(completed_at, created_at), id
69
+ LIMIT ${cap}
70
+ `;
71
+ rows = await prepareDeletableRows(tx, ctx, candidates.map((row) => jobId(row.id)), (ids) => tx `
72
+ SELECT * FROM bunqueue_jobs
73
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
74
+ AND state = 'completed' AND COALESCE(completed_at, created_at) <= ${threshold}
75
+ AND id = ANY(${tx.array(ids.map(String), 'TEXT')})
76
+ ORDER BY COALESCE(completed_at, created_at), id
77
+ `);
78
+ }
79
+ else if (state === 'failed') {
80
+ const candidates = await tx `
81
+ SELECT id FROM bunqueue_jobs
82
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
83
+ AND state = 'failed' AND COALESCE(completed_at, created_at) <= ${threshold}
84
+ ORDER BY COALESCE(completed_at, created_at), id
85
+ LIMIT ${cap}
86
+ `;
87
+ rows = await prepareDeletableRows(tx, ctx, candidates.map((row) => jobId(row.id)), (ids) => tx `
88
+ SELECT * FROM bunqueue_jobs
89
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
90
+ AND state = 'failed' AND COALESCE(completed_at, created_at) <= ${threshold}
91
+ AND id = ANY(${tx.array(ids.map(String), 'TEXT')})
92
+ ORDER BY COALESCE(completed_at, created_at), id
93
+ `);
94
+ }
95
+ else if (state === undefined ||
96
+ state === 'wait' ||
97
+ state === 'waiting' ||
98
+ state === 'delayed' ||
99
+ state === 'prioritized' ||
100
+ state === 'paused') {
101
+ const candidates = await tx `
102
+ SELECT id FROM bunqueue_jobs
103
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
104
+ AND state IN ('waiting', 'prioritized', 'delayed') AND created_at <= ${threshold}
105
+ ORDER BY created_at, id
106
+ LIMIT ${cap}
107
+ `;
108
+ rows = await prepareDeletableRows(tx, ctx, candidates.map((row) => jobId(row.id)), (ids) => tx `
109
+ SELECT * FROM bunqueue_jobs
110
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
111
+ AND state IN ('waiting', 'prioritized', 'delayed') AND created_at <= ${threshold}
112
+ AND id = ANY(${tx.array(ids.map(String), 'TEXT')})
113
+ ORDER BY created_at, id
114
+ `);
115
+ }
116
+ else {
117
+ return [];
118
+ }
119
+ return await deleteRows(tx, ctx, rows);
120
+ });
121
+ }
122
+ /** Permanently remove every failed job currently visible in one queue. */
123
+ export async function purgePostgresDlq(ctx, queue) {
124
+ return await ctx.sql.begin(async (tx) => {
125
+ const candidates = await tx `
126
+ SELECT id FROM bunqueue_jobs
127
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue} AND state = 'failed'
128
+ ORDER BY completed_at, id
129
+ `;
130
+ const rows = await prepareDeletableRows(tx, ctx, candidates.map((row) => jobId(row.id)), (ids) => tx `
131
+ SELECT * FROM bunqueue_jobs
132
+ WHERE namespace = ${ctx.config.namespace} AND queue = ${queue} AND state = 'failed'
133
+ AND id = ANY(${tx.array(ids.map(String), 'TEXT')})
134
+ ORDER BY completed_at, id
135
+ `);
136
+ return await deleteRows(tx, ctx, rows);
137
+ });
138
+ }
@@ -0,0 +1,14 @@
1
+ type MaintenanceReporter = (subsystem: string, error: unknown) => void;
2
+ /** Serialize maintenance per subsystem and drain every admitted execution on close. */
3
+ export declare class PostgresMaintenanceFlights {
4
+ private readonly report;
5
+ private readonly flights;
6
+ private accepting;
7
+ constructor(report: MaintenanceReporter);
8
+ run(subsystem: string, operation: () => Promise<unknown>): Promise<void>;
9
+ close(): void;
10
+ drain(): Promise<void>;
11
+ private replacePending;
12
+ private runLoop;
13
+ }
14
+ export {};
@@ -0,0 +1,66 @@
1
+ /** Serialize maintenance per subsystem and drain every admitted execution on close. */
2
+ export class PostgresMaintenanceFlights {
3
+ report;
4
+ flights = new Map();
5
+ accepting = true;
6
+ constructor(report) {
7
+ this.report = report;
8
+ }
9
+ run(subsystem, operation) {
10
+ if (!this.accepting)
11
+ return Promise.resolve();
12
+ const existing = this.flights.get(subsystem);
13
+ if (existing)
14
+ return this.replacePending(existing, operation);
15
+ let resolve;
16
+ const result = new Promise((accept) => {
17
+ resolve = accept;
18
+ });
19
+ const first = { operation, waiters: [resolve] };
20
+ const flight = {};
21
+ flight.pending = first;
22
+ flight.loop = this.runLoop(subsystem, flight);
23
+ this.flights.set(subsystem, flight);
24
+ return result;
25
+ }
26
+ close() {
27
+ this.accepting = false;
28
+ }
29
+ async drain() {
30
+ await Promise.all([...this.flights.values()].map(({ loop }) => loop));
31
+ }
32
+ replacePending(flight, operation) {
33
+ let resolve;
34
+ const result = new Promise((accept) => {
35
+ resolve = accept;
36
+ });
37
+ if (flight.pending) {
38
+ flight.pending.operation = operation;
39
+ flight.pending.waiters.push(resolve);
40
+ }
41
+ else {
42
+ flight.pending = { operation, waiters: [resolve] };
43
+ }
44
+ return result;
45
+ }
46
+ async runLoop(subsystem, flight) {
47
+ while (flight.pending) {
48
+ const current = flight.pending;
49
+ flight.pending = null;
50
+ try {
51
+ await current.operation();
52
+ this.report(subsystem, null);
53
+ }
54
+ catch (error) {
55
+ this.report(subsystem, error);
56
+ }
57
+ finally {
58
+ for (const resolve of current.waiters)
59
+ resolve();
60
+ }
61
+ await Promise.resolve();
62
+ }
63
+ if (this.flights.get(subsystem) === flight)
64
+ this.flights.delete(subsystem);
65
+ }
66
+ }
@@ -0,0 +1,9 @@
1
+ import type { TransactionSQL } from 'bun';
2
+ import type { QueueMetricType } from '../../../domain/types/metrics';
3
+ import type { PostgresContext } from './context';
4
+ export interface PostgresMetricAddition {
5
+ readonly queue: string;
6
+ readonly count: number;
7
+ }
8
+ /** Update exact durable metrics while minimizing time spent holding shared hot rows. */
9
+ export declare function recordPostgresMetricAdditions(tx: TransactionSQL, ctx: PostgresContext, type: QueueMetricType, inputs: readonly PostgresMetricAddition[], now: number): Promise<void>;
@@ -0,0 +1,94 @@
1
+ function normalizeAdditions(inputs) {
2
+ const counts = new Map();
3
+ for (const input of inputs) {
4
+ if (input.count <= 0)
5
+ continue;
6
+ counts.set(input.queue, (counts.get(input.queue) ?? 0) + input.count);
7
+ }
8
+ return [...counts]
9
+ .map(([queue, count]) => ({ queue, count }))
10
+ .sort((left, right) => left.queue.localeCompare(right.queue));
11
+ }
12
+ async function pruneMetricBuckets(tx, ctx, queues, type, minute) {
13
+ const metricLimit = ctx.config.maxMetricDataPoints;
14
+ await tx `
15
+ DELETE FROM bunqueue_metric_buckets
16
+ WHERE namespace = ${ctx.config.namespace}
17
+ AND queue = ANY(${tx.array([...queues], 'TEXT')})
18
+ AND metric_type = ${type}
19
+ ${metricLimit === 0 ? tx `` : tx `AND minute < ${minute - metricLimit + 1}`}
20
+ `;
21
+ }
22
+ async function updateTotalsWithoutBuckets(tx, ctx, type, additions, now) {
23
+ await tx `
24
+ INSERT INTO bunqueue_metric_totals
25
+ (namespace, queue, metric_type, total_count, prev_ts, prev_count)
26
+ SELECT ${ctx.config.namespace}, batch.queue, ${type}, batch.addition, ${now},
27
+ batch.addition
28
+ FROM unnest(
29
+ ${tx.array(additions.map(({ queue }) => queue), 'TEXT')},
30
+ ${tx.array(additions.map(({ count }) => count), 'INTEGER')}
31
+ ) AS batch(queue, addition)
32
+ ORDER BY batch.queue
33
+ ON CONFLICT (namespace, queue, metric_type) DO UPDATE SET
34
+ total_count = bunqueue_metric_totals.total_count + excluded.total_count,
35
+ prev_ts = GREATEST(bunqueue_metric_totals.prev_ts, excluded.prev_ts),
36
+ prev_count = CASE
37
+ WHEN excluded.prev_ts / 60000 > bunqueue_metric_totals.prev_ts / 60000
38
+ THEN excluded.prev_count
39
+ WHEN excluded.prev_ts / 60000 = bunqueue_metric_totals.prev_ts / 60000
40
+ THEN bunqueue_metric_totals.prev_count + excluded.prev_count
41
+ ELSE bunqueue_metric_totals.prev_count
42
+ END
43
+ `;
44
+ }
45
+ async function updateBucketsAndTotals(tx, ctx, type, additions, now) {
46
+ const minute = Math.floor(now / 60_000);
47
+ await tx `
48
+ WITH incoming AS MATERIALIZED (
49
+ SELECT batch.queue, batch.addition
50
+ FROM unnest(
51
+ ${tx.array(additions.map(({ queue }) => queue), 'TEXT')},
52
+ ${tx.array(additions.map(({ count }) => count), 'INTEGER')}
53
+ ) AS batch(queue, addition)
54
+ ORDER BY batch.queue
55
+ ), buckets AS (
56
+ INSERT INTO bunqueue_metric_buckets
57
+ (namespace, queue, metric_type, minute, count)
58
+ SELECT ${ctx.config.namespace}, incoming.queue, ${type}, ${minute}, incoming.addition
59
+ FROM incoming
60
+ ORDER BY incoming.queue
61
+ ON CONFLICT (namespace, queue, metric_type, minute)
62
+ DO UPDATE SET count = bunqueue_metric_buckets.count + excluded.count
63
+ RETURNING queue, count
64
+ )
65
+ INSERT INTO bunqueue_metric_totals
66
+ (namespace, queue, metric_type, total_count, prev_ts, prev_count)
67
+ SELECT ${ctx.config.namespace}, incoming.queue, ${type}, incoming.addition, ${now},
68
+ buckets.count
69
+ FROM incoming
70
+ JOIN buckets USING (queue)
71
+ ORDER BY incoming.queue
72
+ ON CONFLICT (namespace, queue, metric_type) DO UPDATE SET
73
+ total_count = bunqueue_metric_totals.total_count + excluded.total_count,
74
+ prev_ts = GREATEST(bunqueue_metric_totals.prev_ts, excluded.prev_ts),
75
+ prev_count = CASE
76
+ WHEN excluded.prev_ts / 60000 >= bunqueue_metric_totals.prev_ts / 60000
77
+ THEN excluded.prev_count
78
+ ELSE bunqueue_metric_totals.prev_count
79
+ END
80
+ `;
81
+ }
82
+ /** Update exact durable metrics while minimizing time spent holding shared hot rows. */
83
+ export async function recordPostgresMetricAdditions(tx, ctx, type, inputs, now) {
84
+ const additions = normalizeAdditions(inputs);
85
+ if (additions.length === 0)
86
+ return;
87
+ const minute = Math.floor(now / 60_000);
88
+ await pruneMetricBuckets(tx, ctx, additions.map(({ queue }) => queue), type, minute);
89
+ if (ctx.config.maxMetricDataPoints === 0) {
90
+ await updateTotalsWithoutBuckets(tx, ctx, type, additions, now);
91
+ return;
92
+ }
93
+ await updateBucketsAndTotals(tx, ctx, type, additions, now);
94
+ }
@@ -0,0 +1,9 @@
1
+ import { type JobId } from '../../../domain/types/job';
2
+ import { type PostgresContext } from './context';
3
+ export declare function updatePostgresJobData(ctx: PostgresContext, id: JobId, data: unknown): Promise<boolean>;
4
+ export declare function updatePostgresProgress(ctx: PostgresContext, id: JobId, progress: number, message?: string): Promise<boolean>;
5
+ export declare function changePostgresPriority(ctx: PostgresContext, id: JobId, priority: number, lifo?: boolean): Promise<boolean>;
6
+ export declare function changePostgresDelay(ctx: PostgresContext, id: JobId, runAt: number, token?: string): Promise<boolean>;
7
+ export declare function promotePostgresJob(ctx: PostgresContext, id: JobId): Promise<boolean>;
8
+ export declare function movePostgresJobToWaitingChildren(ctx: PostgresContext, id: JobId, token?: string): Promise<boolean>;
9
+ export declare function clearPostgresJobUniqueKey(ctx: PostgresContext, id: JobId): Promise<boolean>;