bunqueue 2.8.59 → 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.
- package/README.md +109 -77
- package/dist/application/background/dlq.js +2 -0
- package/dist/application/contextFactory.js +5 -0
- package/dist/application/dlqManager.d.ts +11 -1
- package/dist/application/dlqManager.js +48 -10
- package/dist/application/dlqRetry.js +59 -38
- package/dist/application/eventsManager.d.ts +1 -1
- package/dist/application/eventsManager.js +30 -26
- package/dist/application/lockManager.js +1 -1
- package/dist/application/operations/jobManagement.d.ts +4 -0
- package/dist/application/operations/jobMoveOperations.js +9 -4
- package/dist/application/postgres-queue-manager/batchSnapshot.d.ts +16 -0
- package/dist/application/postgres-queue-manager/batchSnapshot.js +17 -0
- package/dist/application/postgres-queue-manager/cloud.d.ts +30 -0
- package/dist/application/postgres-queue-manager/cloud.js +55 -0
- package/dist/application/postgres-queue-manager/config.d.ts +5 -0
- package/dist/application/postgres-queue-manager/config.js +1 -0
- package/dist/application/postgres-queue-manager/control.d.ts +26 -0
- package/dist/application/postgres-queue-manager/control.js +186 -0
- package/dist/application/postgres-queue-manager/deferredWrites.d.ts +13 -0
- package/dist/application/postgres-queue-manager/deferredWrites.js +60 -0
- package/dist/application/postgres-queue-manager/delivery.d.ts +19 -0
- package/dist/application/postgres-queue-manager/delivery.js +80 -0
- package/dist/application/postgres-queue-manager/lease.d.ts +13 -0
- package/dist/application/postgres-queue-manager/lease.js +88 -0
- package/dist/application/postgres-queue-manager/lifetimeMetrics.d.ts +32 -0
- package/dist/application/postgres-queue-manager/lifetimeMetrics.js +53 -0
- package/dist/application/postgres-queue-manager/maintenance.d.ts +14 -0
- package/dist/application/postgres-queue-manager/maintenance.js +100 -0
- package/dist/application/postgres-queue-manager/operationGate.d.ts +26 -0
- package/dist/application/postgres-queue-manager/operationGate.js +96 -0
- package/dist/application/postgres-queue-manager/operations.d.ts +25 -0
- package/dist/application/postgres-queue-manager/operations.js +194 -0
- package/dist/application/postgres-queue-manager/projectionRefreshes.d.ts +43 -0
- package/dist/application/postgres-queue-manager/projectionRefreshes.js +170 -0
- package/dist/application/postgres-queue-manager/queries.d.ts +142 -0
- package/dist/application/postgres-queue-manager/queries.js +231 -0
- package/dist/application/postgres-queue-manager/relationships.d.ts +10 -0
- package/dist/application/postgres-queue-manager/relationships.js +45 -0
- package/dist/application/postgres-queue-manager/services.d.ts +31 -0
- package/dist/application/postgres-queue-manager/services.js +149 -0
- package/dist/application/postgres-queue-manager/snapshot.d.ts +51 -0
- package/dist/application/postgres-queue-manager/snapshot.js +236 -0
- package/dist/application/postgres-queue-manager/snapshotViews.d.ts +15 -0
- package/dist/application/postgres-queue-manager/snapshotViews.js +100 -0
- package/dist/application/postgres-queue-manager/startupEventBuffer.d.ts +12 -0
- package/dist/application/postgres-queue-manager/startupEventBuffer.js +36 -0
- package/dist/application/postgres-queue-manager/state.d.ts +47 -0
- package/dist/application/postgres-queue-manager/state.js +273 -0
- package/dist/application/postgres-queue-manager/terminalDelivery.d.ts +20 -0
- package/dist/application/postgres-queue-manager/terminalDelivery.js +100 -0
- package/dist/application/postgresQueueManager.d.ts +2 -0
- package/dist/application/postgresQueueManager.js +1 -0
- package/dist/application/queue-manager/ack.js +1 -1
- package/dist/application/queue-manager/delivery.js +1 -1
- package/dist/application/queue-manager/flow-failures.js +4 -0
- package/dist/application/queue-manager/limits.d.ts +2 -0
- package/dist/application/queue-manager/limits.js +4 -0
- package/dist/application/queue-manager/observability.js +15 -3
- package/dist/application/queue-manager/queries.d.ts +7 -0
- package/dist/application/queue-manager/queries.js +9 -0
- package/dist/application/queue-manager/services.d.ts +1 -1
- package/dist/application/queue-manager/services.js +4 -2
- package/dist/application/queue-manager/state.js +16 -1
- package/dist/application/statsManager.d.ts +1 -1
- package/dist/application/statsManager.js +1 -1
- package/dist/cli/commands/server.js +1 -1
- package/dist/client/events.js +2 -2
- package/dist/client/flow.js +0 -1
- package/dist/client/forwarder.d.ts +6 -4
- package/dist/client/forwarder.js +5 -3
- package/dist/client/queue/dlq.d.ts +2 -0
- package/dist/client/queue/dlq.js +14 -0
- package/dist/client/queue/dlqOps.d.ts +2 -0
- package/dist/client/queue/dlqOps.js +4 -0
- package/dist/client/queue/helpers.js +2 -0
- package/dist/client/queue/operations/add/single.js +1 -1
- package/dist/client/queue/runtime/configuration.d.ts +4 -0
- package/dist/client/queue/runtime/configuration.js +8 -0
- package/dist/client/sandboxed/runtime/state.js +2 -2
- package/dist/client/tcp/connection.d.ts +1 -1
- package/dist/client/tcp/connection.js +1 -1
- package/dist/client/tcp/runtime/state.js +2 -2
- package/dist/client/types/metrics.d.ts +1 -1
- package/dist/client/worker/runtime/control.js +0 -1
- package/dist/client/worker/runtime/execution.js +3 -8
- package/dist/client/worker/runtime/lifecycle.js +0 -1
- package/dist/client/worker/runtime/polling.d.ts +1 -0
- package/dist/client/worker/runtime/polling.js +9 -0
- package/dist/client/worker/runtime/state.js +3 -3
- package/dist/client/workflow/compensationChild.d.ts +2 -0
- package/dist/client/workflow/compensationChild.js +3 -1
- package/dist/client/workflow/compensationPass.d.ts +1 -0
- package/dist/client/workflow/compensationPass.js +18 -2
- package/dist/client/workflow/compensator.d.ts +2 -1
- package/dist/client/workflow/compensator.js +11 -3
- package/dist/client/workflow/engine.js +1 -1
- package/dist/client/workflow/executionFence.d.ts +15 -0
- package/dist/client/workflow/executionFence.js +29 -0
- package/dist/client/workflow/executor.d.ts +5 -11
- package/dist/client/workflow/executor.js +48 -47
- package/dist/client/workflow/executorLifecycle.d.ts +1 -0
- package/dist/client/workflow/executorLifecycle.js +41 -10
- package/dist/client/workflow/executorNodes.d.ts +1 -0
- package/dist/client/workflow/executorNodes.js +45 -16
- package/dist/client/workflow/executorQueue.d.ts +9 -0
- package/dist/client/workflow/executorQueue.js +15 -0
- package/dist/client/workflow/forEachRunner.d.ts +4 -0
- package/dist/client/workflow/forEachRunner.js +70 -0
- package/dist/client/workflow/loops.d.ts +4 -5
- package/dist/client/workflow/loops.js +27 -93
- package/dist/client/workflow/mapRunner.d.ts +1 -1
- package/dist/client/workflow/mapRunner.js +11 -2
- package/dist/client/workflow/recovery.d.ts +1 -0
- package/dist/client/workflow/recovery.js +24 -18
- package/dist/client/workflow/rollbackControl.d.ts +1 -0
- package/dist/client/workflow/rollbackControl.js +5 -2
- package/dist/client/workflow/runner.d.ts +3 -1
- package/dist/client/workflow/runner.js +26 -3
- package/dist/client/workflow/stepTypes.js +1 -1
- package/dist/client/workflow/subWorkflowRunner.d.ts +1 -0
- package/dist/client/workflow/subWorkflowRunner.js +7 -0
- package/dist/client/workflow/waitFor.d.ts +4 -0
- package/dist/client/workflow/waitFor.js +23 -11
- package/dist/client/workflow/workflowDecisions.d.ts +1 -1
- package/dist/client/workflow/workflowDecisions.js +3 -1
- package/dist/config/resolve.d.ts +14 -0
- package/dist/config/resolve.js +50 -5
- package/dist/config/types.d.ts +18 -0
- package/dist/domain/queue/dlqShard.d.ts +2 -0
- package/dist/domain/queue/dlqShard.js +16 -0
- package/dist/domain/queue/shard/dlq.d.ts +1 -0
- package/dist/domain/queue/shard/dlq.js +3 -0
- package/dist/domain/types/commands/dlq.d.ts +5 -0
- package/dist/domain/types/commands/union.d.ts +1 -1
- package/dist/domain/types/cron.d.ts +5 -0
- package/dist/domain/types/cron.js +14 -3
- package/dist/domain/types/dlq.d.ts +1 -1
- package/dist/domain/types/dlq.js +1 -2
- package/dist/domain/types/jobs/model.d.ts +1 -1
- package/dist/infrastructure/cloud/commandHandler.js +5 -3
- package/dist/infrastructure/cloud/commands/integrations.js +11 -11
- package/dist/infrastructure/cloud/commands/jobs.js +48 -40
- package/dist/infrastructure/cloud/commands/queues.js +61 -75
- package/dist/infrastructure/cloud/queueAdapter/local.d.ts +41 -0
- package/dist/infrastructure/cloud/queueAdapter/local.js +187 -0
- package/dist/infrastructure/cloud/queueAdapter/postgres.d.ts +42 -0
- package/dist/infrastructure/cloud/queueAdapter/postgres.js +188 -0
- package/dist/infrastructure/cloud/queueAdapter/registry.d.ts +4 -0
- package/dist/infrastructure/cloud/queueAdapter/registry.js +15 -0
- package/dist/infrastructure/cloud/queueAdapter/types.d.ts +87 -0
- package/dist/infrastructure/cloud/queueAdapter/types.js +1 -0
- package/dist/infrastructure/cloud/snapshot/analytics.d.ts +2 -0
- package/dist/infrastructure/cloud/snapshot/analytics.js +7 -0
- package/dist/infrastructure/cloud/snapshot/collector.d.ts +4 -0
- package/dist/infrastructure/cloud/snapshot/collector.js +39 -1
- package/dist/infrastructure/cloud/snapshot/config.d.ts +3 -0
- package/dist/infrastructure/cloud/snapshot/config.js +43 -0
- package/dist/infrastructure/cloud/snapshot/jobs.d.ts +3 -0
- package/dist/infrastructure/cloud/snapshot/jobs.js +32 -1
- package/dist/infrastructure/cloud/snapshotCollector.js +20 -35
- package/dist/infrastructure/cloud/snapshotHelpers.d.ts +3 -3
- package/dist/infrastructure/cloud/snapshotHelpers.js +3 -3
- package/dist/infrastructure/cloud/statsRefresh.js +2 -1
- package/dist/infrastructure/cloud/types/command.d.ts +2 -2
- package/dist/infrastructure/persistence/postgres/admission.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/admission.js +193 -0
- package/dist/infrastructure/persistence/postgres/admissionParent.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/admissionParent.js +35 -0
- package/dist/infrastructure/persistence/postgres/admissionResult.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/admissionResult.js +1 -0
- package/dist/infrastructure/persistence/postgres/admissionStore.d.ts +12 -0
- package/dist/infrastructure/persistence/postgres/admissionStore.js +101 -0
- package/dist/infrastructure/persistence/postgres/advisoryLocks.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/advisoryLocks.js +13 -0
- package/dist/infrastructure/persistence/postgres/batchAdmission.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/batchAdmission.js +110 -0
- package/dist/infrastructure/persistence/postgres/batchCompletion.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/batchCompletion.js +174 -0
- package/dist/infrastructure/persistence/postgres/batchEvents.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/batchEvents.js +72 -0
- package/dist/infrastructure/persistence/postgres/brokerSessions.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/brokerSessions.js +94 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.js +56 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.js +198 -0
- package/dist/infrastructure/persistence/postgres/claims.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/claims.js +137 -0
- package/dist/infrastructure/persistence/postgres/cloudReadModel.d.ts +26 -0
- package/dist/infrastructure/persistence/postgres/cloudReadModel.js +123 -0
- package/dist/infrastructure/persistence/postgres/codec.d.ts +30 -0
- package/dist/infrastructure/persistence/postgres/codec.js +82 -0
- package/dist/infrastructure/persistence/postgres/completionEvents.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/completionEvents.js +21 -0
- package/dist/infrastructure/persistence/postgres/completionLifecycle.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/completionLifecycle.js +145 -0
- package/dist/infrastructure/persistence/postgres/completionOutcome.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/completionOutcome.js +112 -0
- package/dist/infrastructure/persistence/postgres/completionQueries.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/completionQueries.js +87 -0
- package/dist/infrastructure/persistence/postgres/connection.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/connection.js +15 -0
- package/dist/infrastructure/persistence/postgres/context.d.ts +28 -0
- package/dist/infrastructure/persistence/postgres/context.js +74 -0
- package/dist/infrastructure/persistence/postgres/control.d.ts +23 -0
- package/dist/infrastructure/persistence/postgres/control.js +105 -0
- package/dist/infrastructure/persistence/postgres/crons.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/crons.js +205 -0
- package/dist/infrastructure/persistence/postgres/deduplication.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/deduplication.js +47 -0
- package/dist/infrastructure/persistence/postgres/dependencyDestruction.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/dependencyDestruction.js +74 -0
- package/dist/infrastructure/persistence/postgres/dependencyPromotion.d.ts +29 -0
- package/dist/infrastructure/persistence/postgres/dependencyPromotion.js +212 -0
- package/dist/infrastructure/persistence/postgres/destructiveMutations.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/destructiveMutations.js +111 -0
- package/dist/infrastructure/persistence/postgres/dlqLifecycle.d.ts +13 -0
- package/dist/infrastructure/persistence/postgres/dlqLifecycle.js +184 -0
- package/dist/infrastructure/persistence/postgres/dlqMaintenance.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/dlqMaintenance.js +36 -0
- package/dist/infrastructure/persistence/postgres/dlqRetryPlan.d.ts +21 -0
- package/dist/infrastructure/persistence/postgres/dlqRetryPlan.js +92 -0
- package/dist/infrastructure/persistence/postgres/eventCommitGc.d.ts +27 -0
- package/dist/infrastructure/persistence/postgres/eventCommitGc.js +62 -0
- package/dist/infrastructure/persistence/postgres/eventJournal.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/eventJournal.js +76 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.js +253 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +24 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +111 -0
- package/dist/infrastructure/persistence/postgres/eventRetention.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/eventRetention.js +76 -0
- package/dist/infrastructure/persistence/postgres/events.d.ts +45 -0
- package/dist/infrastructure/persistence/postgres/events.js +249 -0
- package/dist/infrastructure/persistence/postgres/expiry.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/expiry.js +74 -0
- package/dist/infrastructure/persistence/postgres/flowFailures.d.ts +17 -0
- package/dist/infrastructure/persistence/postgres/flowFailures.js +199 -0
- package/dist/infrastructure/persistence/postgres/jobData.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/jobData.js +32 -0
- package/dist/infrastructure/persistence/postgres/leaseRelease.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/leaseRelease.js +120 -0
- package/dist/infrastructure/persistence/postgres/leaseRenewal.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/leaseRenewal.js +35 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetrics.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetrics.js +46 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.js +13 -0
- package/dist/infrastructure/persistence/postgres/logs.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/logs.js +70 -0
- package/dist/infrastructure/persistence/postgres/maintenance.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/maintenance.js +138 -0
- package/dist/infrastructure/persistence/postgres/maintenanceFlights.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/maintenanceFlights.js +66 -0
- package/dist/infrastructure/persistence/postgres/metricWrites.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/metricWrites.js +94 -0
- package/dist/infrastructure/persistence/postgres/mutations.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/mutations.js +171 -0
- package/dist/infrastructure/persistence/postgres/outcomes.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/outcomes.js +194 -0
- package/dist/infrastructure/persistence/postgres/policies.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/policies.js +18 -0
- package/dist/infrastructure/persistence/postgres/postCommitMaintenance.d.ts +17 -0
- package/dist/infrastructure/persistence/postgres/postCommitMaintenance.js +117 -0
- package/dist/infrastructure/persistence/postgres/promotion.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/promotion.js +43 -0
- package/dist/infrastructure/persistence/postgres/queries.d.ts +22 -0
- package/dist/infrastructure/persistence/postgres/queries.js +152 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.js +154 -0
- package/dist/infrastructure/persistence/postgres/queueLifecycle.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/queueLifecycle.js +60 -0
- package/dist/infrastructure/persistence/postgres/rateLimit.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/rateLimit.js +10 -0
- package/dist/infrastructure/persistence/postgres/readModels.d.ts +32 -0
- package/dist/infrastructure/persistence/postgres/readModels.js +72 -0
- package/dist/infrastructure/persistence/postgres/recovery.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/recovery.js +178 -0
- package/dist/infrastructure/persistence/postgres/relationships.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/relationships.js +201 -0
- package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.js +241 -0
- package/dist/infrastructure/persistence/postgres/repeatMutations.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/repeatMutations.js +37 -0
- package/dist/infrastructure/persistence/postgres/runtime.d.ts +46 -0
- package/dist/infrastructure/persistence/postgres/runtime.js +236 -0
- package/dist/infrastructure/persistence/postgres/runtimeConfig.d.ts +21 -0
- package/dist/infrastructure/persistence/postgres/runtimeConfig.js +39 -0
- package/dist/infrastructure/persistence/postgres/schema.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/schema.js +257 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.js +221 -0
- package/dist/infrastructure/persistence/postgres/serialAdmission.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/serialAdmission.js +96 -0
- package/dist/infrastructure/persistence/postgres/snapshotBudget.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/snapshotBudget.js +83 -0
- package/dist/infrastructure/persistence/postgres/storageHealth.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/storageHealth.js +29 -0
- package/dist/infrastructure/persistence/postgres/store.d.ts +90 -0
- package/dist/infrastructure/persistence/postgres/store.js +136 -0
- package/dist/infrastructure/persistence/postgres/telemetry.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/telemetry.js +88 -0
- package/dist/infrastructure/persistence/postgres/terminal.d.ts +8 -0
- package/dist/infrastructure/persistence/postgres/terminal.js +137 -0
- package/dist/infrastructure/persistence/postgres/transactionRetry.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/transactionRetry.js +42 -0
- package/dist/infrastructure/persistence/postgres/types.d.ts +175 -0
- package/dist/infrastructure/persistence/postgres/types.js +1 -0
- package/dist/infrastructure/persistence/postgres/workers.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/workers.js +126 -0
- package/dist/infrastructure/persistence/postgres.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres.js +1 -0
- package/dist/infrastructure/persistence/sqlite/jobs.js +2 -0
- package/dist/infrastructure/persistence/sqlite.d.ts +1 -1
- package/dist/infrastructure/scheduler/cron/persisted.d.ts +5 -0
- package/dist/infrastructure/scheduler/cron/persisted.js +27 -0
- package/dist/infrastructure/scheduler/cron/runtime.js +5 -10
- package/dist/infrastructure/scheduler/cron/validation.d.ts +3 -0
- package/dist/infrastructure/scheduler/cron/validation.js +11 -0
- package/dist/infrastructure/scheduler/cronParser.d.ts +1 -1
- package/dist/infrastructure/scheduler/cronParser.js +144 -11
- package/dist/infrastructure/server/bootstrap.d.ts +2 -3
- package/dist/infrastructure/server/bootstrap.js +33 -59
- package/dist/infrastructure/server/errors.d.ts +4 -0
- package/dist/infrastructure/server/errors.js +54 -0
- package/dist/infrastructure/server/handler-routes/control.d.ts +5 -5
- package/dist/infrastructure/server/handler-routes/control.js +3 -1
- package/dist/infrastructure/server/handler-routes/jobs.js +0 -3
- package/dist/infrastructure/server/handler-routes/monitoring.d.ts +2 -2
- package/dist/infrastructure/server/handler.js +9 -11
- package/dist/infrastructure/server/handlerRoutes.d.ts +2 -2
- package/dist/infrastructure/server/handlerRoutes.js +2 -2
- package/dist/infrastructure/server/handlers/advanced/dependencies.js +7 -6
- package/dist/infrastructure/server/handlers/advanced/jobs.js +19 -6
- package/dist/infrastructure/server/handlers/advanced/queue.d.ts +9 -9
- package/dist/infrastructure/server/handlers/advanced/queue.js +91 -27
- package/dist/infrastructure/server/handlers/core.js +32 -31
- package/dist/infrastructure/server/handlers/cron.d.ts +4 -4
- package/dist/infrastructure/server/handlers/cron.js +60 -59
- package/dist/infrastructure/server/handlers/dashboard.d.ts +1 -1
- package/dist/infrastructure/server/handlers/dashboard.js +21 -8
- package/dist/infrastructure/server/handlers/dlq.d.ts +6 -3
- package/dist/infrastructure/server/handlers/dlq.js +35 -9
- package/dist/infrastructure/server/handlers/flow.js +2 -1
- package/dist/infrastructure/server/handlers/management.d.ts +5 -5
- package/dist/infrastructure/server/handlers/management.js +36 -9
- package/dist/infrastructure/server/handlers/monitoring/health.d.ts +5 -5
- package/dist/infrastructure/server/handlers/monitoring/health.js +45 -16
- package/dist/infrastructure/server/handlers/monitoring/operations.d.ts +1 -1
- package/dist/infrastructure/server/handlers/monitoring/operations.js +8 -1
- package/dist/infrastructure/server/handlers/monitoring/workers.d.ts +3 -3
- package/dist/infrastructure/server/handlers/monitoring/workers.js +31 -7
- package/dist/infrastructure/server/handlers/pushBatchValidation.d.ts +3 -1
- package/dist/infrastructure/server/handlers/pushBatchValidation.js +52 -7
- package/dist/infrastructure/server/handlers/query.d.ts +1 -1
- package/dist/infrastructure/server/handlers/query.js +5 -4
- package/dist/infrastructure/server/http.js +2 -2
- package/dist/infrastructure/server/httpDashboardEndpoints.d.ts +1 -1
- package/dist/infrastructure/server/httpDashboardEndpoints.js +19 -6
- package/dist/infrastructure/server/httpEndpoints.js +20 -7
- package/dist/infrastructure/server/httpRouteQueues.js +11 -1
- package/dist/infrastructure/server/shutdownCoordinator.d.ts +24 -0
- package/dist/infrastructure/server/shutdownCoordinator.js +106 -0
- package/dist/infrastructure/server/sseHandler.js +8 -3
- package/dist/infrastructure/server/storageAdapter.d.ts +29 -0
- package/dist/infrastructure/server/storageAdapter.js +61 -0
- package/dist/infrastructure/server/storageManager.d.ts +12 -0
- package/dist/infrastructure/server/storageManager.js +102 -0
- package/dist/infrastructure/server/tcp.js +2 -3
- package/dist/infrastructure/server/ws/snapshots.d.ts +1 -1
- package/dist/infrastructure/server/ws/snapshots.js +19 -4
- package/dist/infrastructure/server/wsHandler.js +10 -5
- package/dist/main.js +1 -1
- package/dist/mcp/backend/embedded/services.js +2 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +2 -2
- package/dist/shared/storageHealth.d.ts +9 -0
- package/dist/shared/storageHealth.js +12 -0
- package/package.json +85 -74
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { jobId } from '../../../domain/types/job';
|
|
2
|
+
import { decodePostgresJob, decodePostgresValue, numeric } from './codec';
|
|
3
|
+
export async function getPostgresJob(ctx, id) {
|
|
4
|
+
const rows = await ctx.sql `
|
|
5
|
+
SELECT * FROM bunqueue_jobs
|
|
6
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${String(id)}
|
|
7
|
+
`;
|
|
8
|
+
return rows[0] ? decodePostgresJob(rows[0]) : null;
|
|
9
|
+
}
|
|
10
|
+
export async function getPostgresJobs(ctx, ids, sql = ctx.sql) {
|
|
11
|
+
if (ids.length === 0)
|
|
12
|
+
return [];
|
|
13
|
+
const rows = await sql `
|
|
14
|
+
SELECT * FROM bunqueue_jobs
|
|
15
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
16
|
+
AND id = ANY(${sql.array([...new Set(ids.map(String))], 'TEXT')})
|
|
17
|
+
`;
|
|
18
|
+
return rows.map(decodePostgresJob);
|
|
19
|
+
}
|
|
20
|
+
/** Return dependency ids that have neither a job row nor durable completion evidence. */
|
|
21
|
+
export async function findMissingPostgresDependencies(ctx, ids) {
|
|
22
|
+
const requested = [...new Set(ids.map(String))];
|
|
23
|
+
if (requested.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
const rows = await ctx.sql `
|
|
26
|
+
WITH requested(id) AS MATERIALIZED (
|
|
27
|
+
SELECT DISTINCT id
|
|
28
|
+
FROM unnest(${ctx.sql.array(requested, 'TEXT')}) AS dependency(id)
|
|
29
|
+
)
|
|
30
|
+
SELECT requested.id
|
|
31
|
+
FROM requested
|
|
32
|
+
WHERE NOT EXISTS (
|
|
33
|
+
SELECT 1 FROM bunqueue_jobs AS job
|
|
34
|
+
WHERE job.namespace = ${ctx.config.namespace} AND job.id = requested.id
|
|
35
|
+
) AND NOT EXISTS (
|
|
36
|
+
SELECT 1 FROM bunqueue_completions AS completion
|
|
37
|
+
WHERE completion.namespace = ${ctx.config.namespace}
|
|
38
|
+
AND completion.job_id = requested.id
|
|
39
|
+
)
|
|
40
|
+
`;
|
|
41
|
+
return rows.map((row) => jobId(row.id));
|
|
42
|
+
}
|
|
43
|
+
export async function listPostgresJobs(ctx, queue, options = {}, sql = ctx.sql) {
|
|
44
|
+
const states = options.states ?? [
|
|
45
|
+
'waiting',
|
|
46
|
+
'prioritized',
|
|
47
|
+
'delayed',
|
|
48
|
+
'waiting-children',
|
|
49
|
+
'active',
|
|
50
|
+
'completed',
|
|
51
|
+
'failed',
|
|
52
|
+
];
|
|
53
|
+
if (states.length === 0)
|
|
54
|
+
return [];
|
|
55
|
+
const stateArray = ctx.sql.array([...states], 'TEXT');
|
|
56
|
+
const limit = Math.max(0, options.limit ?? 1000);
|
|
57
|
+
const offset = Math.max(0, options.offset ?? 0);
|
|
58
|
+
const rows = options.asc
|
|
59
|
+
? await sql `
|
|
60
|
+
SELECT * FROM bunqueue_jobs
|
|
61
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
62
|
+
AND queue = ${queue}
|
|
63
|
+
AND state = ANY(${stateArray})
|
|
64
|
+
ORDER BY created_at ASC, id ASC
|
|
65
|
+
LIMIT ${limit} OFFSET ${offset}
|
|
66
|
+
`
|
|
67
|
+
: await sql `
|
|
68
|
+
SELECT * FROM bunqueue_jobs
|
|
69
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
70
|
+
AND queue = ${queue}
|
|
71
|
+
AND state = ANY(${stateArray})
|
|
72
|
+
ORDER BY created_at DESC, id DESC
|
|
73
|
+
LIMIT ${limit} OFFSET ${offset}
|
|
74
|
+
`;
|
|
75
|
+
return rows.map(decodePostgresJob);
|
|
76
|
+
}
|
|
77
|
+
export async function loadAllPostgresJobs(ctx, sql = ctx.sql) {
|
|
78
|
+
const rows = await sql `
|
|
79
|
+
WITH retained_completed AS MATERIALIZED (
|
|
80
|
+
SELECT * FROM bunqueue_jobs
|
|
81
|
+
WHERE namespace = ${ctx.config.namespace} AND state = 'completed'
|
|
82
|
+
ORDER BY completed_at DESC NULLS LAST, id DESC
|
|
83
|
+
LIMIT ${ctx.config.maxCompletedJobs}
|
|
84
|
+
)
|
|
85
|
+
SELECT * FROM (
|
|
86
|
+
SELECT * FROM bunqueue_jobs
|
|
87
|
+
WHERE namespace = ${ctx.config.namespace} AND state <> 'completed'
|
|
88
|
+
UNION ALL
|
|
89
|
+
SELECT * FROM retained_completed
|
|
90
|
+
) AS retained_jobs
|
|
91
|
+
ORDER BY created_at, id
|
|
92
|
+
`;
|
|
93
|
+
return rows.map(decodePostgresJob);
|
|
94
|
+
}
|
|
95
|
+
export async function getPostgresCounts(ctx, queue) {
|
|
96
|
+
const rows = queue
|
|
97
|
+
? await ctx.sql `
|
|
98
|
+
SELECT state, COUNT(*)::bigint AS count
|
|
99
|
+
FROM bunqueue_jobs
|
|
100
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
101
|
+
GROUP BY state
|
|
102
|
+
`
|
|
103
|
+
: await ctx.sql `
|
|
104
|
+
SELECT state, COUNT(*)::bigint AS count
|
|
105
|
+
FROM bunqueue_jobs
|
|
106
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
107
|
+
GROUP BY state
|
|
108
|
+
`;
|
|
109
|
+
const byState = new Map(rows.map((row) => [row.state, Number(row.count)]));
|
|
110
|
+
return {
|
|
111
|
+
waiting: byState.get('waiting') ?? 0,
|
|
112
|
+
active: byState.get('active') ?? 0,
|
|
113
|
+
completed: byState.get('completed') ?? 0,
|
|
114
|
+
failed: byState.get('failed') ?? 0,
|
|
115
|
+
delayed: byState.get('delayed') ?? 0,
|
|
116
|
+
prioritized: byState.get('prioritized') ?? 0,
|
|
117
|
+
waitingChildren: byState.get('waiting-children') ?? 0,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export async function listPostgresQueues(ctx, sql = ctx.sql) {
|
|
121
|
+
const rows = await sql `
|
|
122
|
+
SELECT queue FROM bunqueue_jobs WHERE namespace = ${ctx.config.namespace}
|
|
123
|
+
UNION
|
|
124
|
+
SELECT queue FROM bunqueue_queue_state WHERE namespace = ${ctx.config.namespace}
|
|
125
|
+
ORDER BY queue
|
|
126
|
+
`;
|
|
127
|
+
return rows.map((row) => row.queue);
|
|
128
|
+
}
|
|
129
|
+
export async function listPostgresDlq(ctx, queue, limit = 1000) {
|
|
130
|
+
const rows = await ctx.sql `
|
|
131
|
+
SELECT id, dlq_entry FROM bunqueue_jobs
|
|
132
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
133
|
+
AND queue = ${queue}
|
|
134
|
+
AND state = 'failed'
|
|
135
|
+
AND dlq_entry IS NOT NULL
|
|
136
|
+
ORDER BY completed_at DESC, id DESC
|
|
137
|
+
LIMIT ${Math.max(0, limit)}
|
|
138
|
+
`;
|
|
139
|
+
return rows.flatMap((row) => {
|
|
140
|
+
const entry = decodePostgresValue(row.dlq_entry, null, `postgresDlq:${row.id}`);
|
|
141
|
+
return entry ? [entry] : [];
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
export async function latestPostgresEventId(ctx) {
|
|
145
|
+
const [row] = await ctx.sql `
|
|
146
|
+
SELECT MAX(id) AS id FROM bunqueue_events WHERE namespace = ${ctx.config.namespace}
|
|
147
|
+
`;
|
|
148
|
+
return numeric(row.id) ?? 0;
|
|
149
|
+
}
|
|
150
|
+
export function jobsOnly(rows) {
|
|
151
|
+
return rows.map((row) => row.job);
|
|
152
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { jobId } from '../../../domain/types/job';
|
|
2
|
+
import { databaseNow, recordPostgresEvent } from './context';
|
|
3
|
+
import { lockPostgresDestructionCandidates, lockPostgresDestructionIdentities, lockPostgresDestructionRows, partitionPostgresDestructionCandidates, } from './dependencyDestruction';
|
|
4
|
+
import { deletePostgresEventPruneWatermark } from './eventPruneWatermarks';
|
|
5
|
+
import { lockPostgresQueueLifecycleExclusive } from './queueLifecycle';
|
|
6
|
+
import { deletePostgresQueueEventHistory, lockPostgresEventRetention } from './eventRetention';
|
|
7
|
+
async function recordQueueInvalidation(tx, ctx, queue, type) {
|
|
8
|
+
await recordPostgresEvent(tx, ctx, {
|
|
9
|
+
queue,
|
|
10
|
+
type,
|
|
11
|
+
jobId: jobId(`__queue__:${queue}`),
|
|
12
|
+
occurredAt: await databaseNow(tx),
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
export async function drainPostgresQueue(ctx, queue) {
|
|
16
|
+
return await ctx.sql.begin(async (tx) => {
|
|
17
|
+
const candidates = await tx `
|
|
18
|
+
SELECT id FROM bunqueue_jobs
|
|
19
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
20
|
+
AND state IN ('waiting', 'prioritized', 'delayed', 'waiting-children')
|
|
21
|
+
ORDER BY id
|
|
22
|
+
`;
|
|
23
|
+
const candidateIds = candidates.map((row) => jobId(row.id));
|
|
24
|
+
if (candidateIds.length === 0)
|
|
25
|
+
return 0;
|
|
26
|
+
await lockPostgresDestructionCandidates(tx, ctx, candidateIds);
|
|
27
|
+
const rows = await tx `
|
|
28
|
+
SELECT id FROM bunqueue_jobs
|
|
29
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
30
|
+
AND state IN ('waiting', 'prioritized', 'delayed', 'waiting-children')
|
|
31
|
+
AND id = ANY(${tx.array(candidateIds.map(String), 'TEXT')})
|
|
32
|
+
ORDER BY id
|
|
33
|
+
`;
|
|
34
|
+
const plannedIds = rows.map((row) => jobId(row.id));
|
|
35
|
+
const { deletableIds } = await partitionPostgresDestructionCandidates(tx, ctx, plannedIds, plannedIds);
|
|
36
|
+
const ids = deletableIds.map(String);
|
|
37
|
+
if (ids.length === 0)
|
|
38
|
+
return 0;
|
|
39
|
+
const values = tx.array(ids, 'TEXT');
|
|
40
|
+
await tx `
|
|
41
|
+
DELETE FROM bunqueue_job_logs
|
|
42
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${values})
|
|
43
|
+
`;
|
|
44
|
+
await tx `
|
|
45
|
+
DELETE FROM bunqueue_flow_failures
|
|
46
|
+
WHERE namespace = ${ctx.config.namespace} AND parent_id = ANY(${values})
|
|
47
|
+
`;
|
|
48
|
+
await tx `
|
|
49
|
+
DELETE FROM bunqueue_dependencies
|
|
50
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${values})
|
|
51
|
+
`;
|
|
52
|
+
await tx `
|
|
53
|
+
DELETE FROM bunqueue_jobs
|
|
54
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ANY(${values})
|
|
55
|
+
`;
|
|
56
|
+
await recordQueueInvalidation(tx, ctx, queue, 'queue-drained');
|
|
57
|
+
return ids.length;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
export async function obliteratePostgresQueue(ctx, queue) {
|
|
61
|
+
return await ctx.sql.begin(async (tx) => {
|
|
62
|
+
await lockPostgresQueueLifecycleExclusive(tx, ctx, queue);
|
|
63
|
+
await lockPostgresEventRetention(tx, ctx, queue);
|
|
64
|
+
await tx `
|
|
65
|
+
INSERT INTO bunqueue_queue_state (namespace, queue)
|
|
66
|
+
VALUES (${ctx.config.namespace}, ${queue})
|
|
67
|
+
ON CONFLICT (namespace, queue) DO NOTHING
|
|
68
|
+
`;
|
|
69
|
+
await tx `
|
|
70
|
+
SELECT queue FROM bunqueue_queue_state
|
|
71
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
72
|
+
FOR UPDATE
|
|
73
|
+
`;
|
|
74
|
+
const candidates = await tx `
|
|
75
|
+
SELECT id FROM (
|
|
76
|
+
SELECT id FROM bunqueue_jobs
|
|
77
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
78
|
+
UNION
|
|
79
|
+
SELECT job_id AS id FROM bunqueue_completions
|
|
80
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
81
|
+
) AS queue_ids
|
|
82
|
+
ORDER BY id
|
|
83
|
+
`;
|
|
84
|
+
const candidateIds = candidates.map((row) => jobId(row.id));
|
|
85
|
+
await lockPostgresDestructionIdentities(tx, ctx, candidateIds);
|
|
86
|
+
await lockPostgresDestructionRows(tx, ctx, candidateIds);
|
|
87
|
+
const jobs = await tx `
|
|
88
|
+
SELECT id FROM bunqueue_jobs
|
|
89
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
90
|
+
AND id = ANY(${tx.array(candidateIds.map(String), 'TEXT')})
|
|
91
|
+
ORDER BY id
|
|
92
|
+
`;
|
|
93
|
+
const completions = await tx `
|
|
94
|
+
SELECT job_id FROM bunqueue_completions
|
|
95
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
96
|
+
AND job_id = ANY(${tx.array(candidateIds.map(String), 'TEXT')})
|
|
97
|
+
ORDER BY job_id
|
|
98
|
+
`;
|
|
99
|
+
const jobIds = jobs.map((row) => jobId(row.id));
|
|
100
|
+
const targetIds = [
|
|
101
|
+
...new Set([...jobIds.map(String), ...completions.map((row) => row.job_id)]),
|
|
102
|
+
].map(jobId);
|
|
103
|
+
const { protectedIds } = await partitionPostgresDestructionCandidates(tx, ctx, targetIds, jobIds);
|
|
104
|
+
if (protectedIds.length > 0) {
|
|
105
|
+
throw new Error(`Cannot obliterate queue ${queue}: ${protectedIds.length} job(s) have live dependents`);
|
|
106
|
+
}
|
|
107
|
+
const targets = tx.array(targetIds.map(String), 'TEXT');
|
|
108
|
+
const jobValues = tx.array(jobIds.map(String), 'TEXT');
|
|
109
|
+
if (targetIds.length > 0) {
|
|
110
|
+
await tx `
|
|
111
|
+
DELETE FROM bunqueue_job_logs
|
|
112
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${targets})
|
|
113
|
+
`;
|
|
114
|
+
await tx `
|
|
115
|
+
DELETE FROM bunqueue_repeat_links
|
|
116
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
117
|
+
AND (original_id = ANY(${targets}) OR successor_id = ANY(${targets}))
|
|
118
|
+
`;
|
|
119
|
+
await tx `
|
|
120
|
+
DELETE FROM bunqueue_flow_failures
|
|
121
|
+
WHERE namespace = ${ctx.config.namespace} AND parent_id = ANY(${targets})
|
|
122
|
+
`;
|
|
123
|
+
await tx `
|
|
124
|
+
DELETE FROM bunqueue_dependencies
|
|
125
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
126
|
+
AND (job_id = ANY(${jobValues}) OR dependency_id = ANY(${targets}))
|
|
127
|
+
`;
|
|
128
|
+
await tx `
|
|
129
|
+
DELETE FROM bunqueue_completions
|
|
130
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${targets})
|
|
131
|
+
`;
|
|
132
|
+
await tx `
|
|
133
|
+
DELETE FROM bunqueue_jobs
|
|
134
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ANY(${jobValues})
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
await tx `
|
|
138
|
+
DELETE FROM bunqueue_queue_state
|
|
139
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
140
|
+
`;
|
|
141
|
+
await tx `
|
|
142
|
+
DELETE FROM bunqueue_metric_buckets
|
|
143
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
144
|
+
`;
|
|
145
|
+
await tx `
|
|
146
|
+
DELETE FROM bunqueue_metric_totals
|
|
147
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
148
|
+
`;
|
|
149
|
+
await deletePostgresQueueEventHistory(tx, ctx, queue);
|
|
150
|
+
await deletePostgresEventPruneWatermark(tx, ctx, queue);
|
|
151
|
+
await recordQueueInvalidation(tx, ctx, queue, 'queue-obliterated');
|
|
152
|
+
return jobIds.length;
|
|
153
|
+
});
|
|
154
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { TransactionSQL } from 'bun';
|
|
2
|
+
import type { PostgresContext } from './context';
|
|
3
|
+
/** Acquire queue lifecycle locks before admission identity or row locks. */
|
|
4
|
+
export declare function lockPostgresAdmissionQueues(tx: TransactionSQL, ctx: PostgresContext, queues: readonly string[]): Promise<void>;
|
|
5
|
+
/** Persist queue identity only after admission has proved it inserted a generation. */
|
|
6
|
+
export declare function registerPostgresAdmissionQueues(tx: TransactionSQL, ctx: PostgresContext, queues: readonly string[]): Promise<void>;
|
|
7
|
+
/** Exclusively serialize queue deletion against every new admission. */
|
|
8
|
+
export declare function lockPostgresQueueLifecycleExclusive(tx: TransactionSQL, ctx: PostgresContext, queue: string): Promise<void>;
|
|
9
|
+
/** Try a late shared lock so repeat ACKs roll back instead of deadlocking deletion. */
|
|
10
|
+
export declare function tryLockPostgresRepeatQueues(tx: TransactionSQL, ctx: PostgresContext, queues: readonly string[]): Promise<boolean>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { postgresAdvisoryLockName } from './advisoryLocks';
|
|
2
|
+
function queueNames(queues) {
|
|
3
|
+
return [...new Set(queues)].sort();
|
|
4
|
+
}
|
|
5
|
+
/** Acquire queue lifecycle locks before admission identity or row locks. */
|
|
6
|
+
export async function lockPostgresAdmissionQueues(tx, ctx, queues) {
|
|
7
|
+
const lockNames = queueNames(queues).map((queue) => postgresAdvisoryLockName('queue-lifecycle', ctx.config.namespace, queue));
|
|
8
|
+
if (lockNames.length === 0)
|
|
9
|
+
return;
|
|
10
|
+
await tx `
|
|
11
|
+
WITH ordered_queues AS MATERIALIZED (
|
|
12
|
+
SELECT DISTINCT hashtextextended(lock_name, 0) AS lock_key
|
|
13
|
+
FROM unnest(${tx.array(lockNames, 'TEXT')}) AS requested(lock_name)
|
|
14
|
+
ORDER BY lock_key
|
|
15
|
+
), locked_queues AS MATERIALIZED (
|
|
16
|
+
SELECT lock_key, pg_advisory_xact_lock_shared(lock_key) AS acquired
|
|
17
|
+
FROM ordered_queues
|
|
18
|
+
ORDER BY lock_key
|
|
19
|
+
)
|
|
20
|
+
SELECT COUNT(*) FROM locked_queues
|
|
21
|
+
`;
|
|
22
|
+
}
|
|
23
|
+
/** Persist queue identity only after admission has proved it inserted a generation. */
|
|
24
|
+
export async function registerPostgresAdmissionQueues(tx, ctx, queues) {
|
|
25
|
+
const names = queueNames(queues);
|
|
26
|
+
if (names.length === 0)
|
|
27
|
+
return;
|
|
28
|
+
await tx `
|
|
29
|
+
INSERT INTO bunqueue_queue_state (namespace, queue)
|
|
30
|
+
SELECT ${ctx.config.namespace}, queue
|
|
31
|
+
FROM unnest(${tx.array(names, 'TEXT')}) AS admitted(queue)
|
|
32
|
+
ON CONFLICT (namespace, queue) DO NOTHING
|
|
33
|
+
`;
|
|
34
|
+
}
|
|
35
|
+
/** Exclusively serialize queue deletion against every new admission. */
|
|
36
|
+
export async function lockPostgresQueueLifecycleExclusive(tx, ctx, queue) {
|
|
37
|
+
const lockName = postgresAdvisoryLockName('queue-lifecycle', ctx.config.namespace, queue);
|
|
38
|
+
await tx `
|
|
39
|
+
SELECT pg_advisory_xact_lock(hashtextextended(${lockName}, 0))
|
|
40
|
+
`;
|
|
41
|
+
}
|
|
42
|
+
/** Try a late shared lock so repeat ACKs roll back instead of deadlocking deletion. */
|
|
43
|
+
export async function tryLockPostgresRepeatQueues(tx, ctx, queues) {
|
|
44
|
+
const lockNames = queueNames(queues).map((queue) => postgresAdvisoryLockName('queue-lifecycle', ctx.config.namespace, queue));
|
|
45
|
+
if (lockNames.length === 0)
|
|
46
|
+
return true;
|
|
47
|
+
const [result] = await tx `
|
|
48
|
+
WITH ordered_queues AS MATERIALIZED (
|
|
49
|
+
SELECT DISTINCT hashtextextended(lock_name, 0) AS lock_key
|
|
50
|
+
FROM unnest(${tx.array(lockNames, 'TEXT')}) AS requested(lock_name)
|
|
51
|
+
ORDER BY lock_key
|
|
52
|
+
), attempted AS MATERIALIZED (
|
|
53
|
+
SELECT lock_key, pg_try_advisory_xact_lock_shared(lock_key) AS acquired
|
|
54
|
+
FROM ordered_queues
|
|
55
|
+
ORDER BY lock_key
|
|
56
|
+
)
|
|
57
|
+
SELECT COALESCE(bool_and(acquired), TRUE) AS acquired FROM attempted
|
|
58
|
+
`;
|
|
59
|
+
return result.acquired;
|
|
60
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface NormalizedPostgresRateLimit {
|
|
2
|
+
readonly durationMs: number | null;
|
|
3
|
+
readonly ttlMs: number | null;
|
|
4
|
+
}
|
|
5
|
+
/** Match the in-memory limiter's handling of optional duration and TTL windows. */
|
|
6
|
+
export declare function normalizePostgresRateLimit(durationMs: number | null | undefined, ttlMs: number | null | undefined): NormalizedPostgresRateLimit;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
function positiveFinite(value) {
|
|
2
|
+
return Number.isFinite(value) && value > 0 ? value : null;
|
|
3
|
+
}
|
|
4
|
+
/** Match the in-memory limiter's handling of optional duration and TTL windows. */
|
|
5
|
+
export function normalizePostgresRateLimit(durationMs, ttlMs) {
|
|
6
|
+
return {
|
|
7
|
+
durationMs: positiveFinite(durationMs),
|
|
8
|
+
ttlMs: positiveFinite(ttlMs),
|
|
9
|
+
};
|
|
10
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { CronJob } from '../../../domain/types/cron';
|
|
2
|
+
import type { JobId } from '../../../domain/types/job';
|
|
3
|
+
import type { PostgresContext } from './context';
|
|
4
|
+
import { type PostgresLifetimeMetricsSnapshot } from './lifetimeMetrics';
|
|
5
|
+
import type { PostgresCompletionResult, PostgresQueueState, PostgresStoredJob } from './types';
|
|
6
|
+
export interface PostgresManagerSnapshot {
|
|
7
|
+
readonly rows: readonly PostgresStoredJob[];
|
|
8
|
+
readonly results: readonly PostgresCompletionResult[];
|
|
9
|
+
readonly crons: readonly CronJob[];
|
|
10
|
+
readonly states: readonly PostgresQueueState[];
|
|
11
|
+
readonly lifetimeMetrics: PostgresLifetimeMetricsSnapshot;
|
|
12
|
+
}
|
|
13
|
+
export interface PostgresQueueReadModel {
|
|
14
|
+
readonly rows: readonly PostgresStoredJob[];
|
|
15
|
+
readonly results: readonly PostgresCompletionResult[];
|
|
16
|
+
readonly state: PostgresQueueState;
|
|
17
|
+
readonly exists: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface PostgresProjectionRequest {
|
|
20
|
+
readonly id: JobId;
|
|
21
|
+
readonly queue: string;
|
|
22
|
+
}
|
|
23
|
+
export interface PostgresJobProjection {
|
|
24
|
+
readonly row: PostgresStoredJob | null;
|
|
25
|
+
readonly completion: PostgresCompletionResult | null;
|
|
26
|
+
}
|
|
27
|
+
/** Load one transactionally coherent manager bootstrap projection. */
|
|
28
|
+
export declare function loadPostgresManagerSnapshot(ctx: PostgresContext): Promise<PostgresManagerSnapshot>;
|
|
29
|
+
/** Load jobs, results, and policy for one queue from the same MVCC snapshot. */
|
|
30
|
+
export declare function loadPostgresQueueReadModel(ctx: PostgresContext, queue: string): Promise<PostgresQueueReadModel>;
|
|
31
|
+
/** Batch current rows and consult completion evidence only for removed jobs. */
|
|
32
|
+
export declare function loadPostgresJobProjections(ctx: PostgresContext, requests: readonly PostgresProjectionRequest[]): Promise<ReadonlyMap<JobId, PostgresJobProjection>>;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { decodePostgresValue } from './codec';
|
|
2
|
+
import { loadPostgresCompletionResults } from './completionQueries';
|
|
3
|
+
import { getPostgresQueueState } from './control';
|
|
4
|
+
import { listPostgresCrons } from './crons';
|
|
5
|
+
import { loadPostgresLifetimeMetrics, } from './lifetimeMetrics';
|
|
6
|
+
import { getPostgresJobs, listPostgresJobs, listPostgresQueues, loadAllPostgresJobs, } from './queries';
|
|
7
|
+
import { assertPostgresSnapshotBudget } from './snapshotBudget';
|
|
8
|
+
/** Load one transactionally coherent manager bootstrap projection. */
|
|
9
|
+
export async function loadPostgresManagerSnapshot(ctx) {
|
|
10
|
+
return await ctx.sql.begin('isolation level repeatable read read only', async (tx) => {
|
|
11
|
+
await assertPostgresSnapshotBudget(ctx, tx);
|
|
12
|
+
const [rows, results, crons, queues, lifetimeMetrics] = await Promise.all([
|
|
13
|
+
loadAllPostgresJobs(ctx, tx),
|
|
14
|
+
loadPostgresCompletionResults(ctx, undefined, tx),
|
|
15
|
+
listPostgresCrons(ctx, tx),
|
|
16
|
+
listPostgresQueues(ctx, tx),
|
|
17
|
+
loadPostgresLifetimeMetrics(ctx, tx),
|
|
18
|
+
]);
|
|
19
|
+
const states = await Promise.all(queues.map((queue) => getPostgresQueueState(ctx, queue, tx)));
|
|
20
|
+
return { rows, results, crons, states, lifetimeMetrics };
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/** Load jobs, results, and policy for one queue from the same MVCC snapshot. */
|
|
24
|
+
export async function loadPostgresQueueReadModel(ctx, queue) {
|
|
25
|
+
return await ctx.sql.begin('isolation level repeatable read read only', async (tx) => {
|
|
26
|
+
await assertPostgresSnapshotBudget(ctx, tx, queue);
|
|
27
|
+
const [rows, results, state, [presence]] = await Promise.all([
|
|
28
|
+
listPostgresJobs(ctx, queue, { limit: 2_147_483_647, asc: true }, tx),
|
|
29
|
+
loadPostgresCompletionResults(ctx, queue, tx),
|
|
30
|
+
getPostgresQueueState(ctx, queue, tx),
|
|
31
|
+
tx `
|
|
32
|
+
SELECT EXISTS (
|
|
33
|
+
SELECT 1 FROM bunqueue_jobs
|
|
34
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
35
|
+
UNION ALL
|
|
36
|
+
SELECT 1 FROM bunqueue_queue_state
|
|
37
|
+
WHERE namespace = ${ctx.config.namespace} AND queue = ${queue}
|
|
38
|
+
) AS exists
|
|
39
|
+
`,
|
|
40
|
+
]);
|
|
41
|
+
return { rows, results, state, exists: presence.exists };
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** Batch current rows and consult completion evidence only for removed jobs. */
|
|
45
|
+
export async function loadPostgresJobProjections(ctx, requests) {
|
|
46
|
+
if (requests.length === 0)
|
|
47
|
+
return new Map();
|
|
48
|
+
const rows = await getPostgresJobs(ctx, requests.map(({ id }) => id));
|
|
49
|
+
const byId = new Map(rows.map((row) => [row.job.id, row]));
|
|
50
|
+
const missing = requests.filter(({ id }) => !byId.has(id));
|
|
51
|
+
const completions = missing.length === 0
|
|
52
|
+
? []
|
|
53
|
+
: await ctx.sql `
|
|
54
|
+
SELECT job_id, queue, result FROM bunqueue_completions
|
|
55
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
56
|
+
AND job_id = ANY(${ctx.sql.array(missing.map(({ id }) => String(id)), 'TEXT')})
|
|
57
|
+
`;
|
|
58
|
+
const completionById = new Map(completions.map((row) => [row.job_id, row]));
|
|
59
|
+
return new Map(requests.map(({ id }) => {
|
|
60
|
+
const row = byId.get(id) ?? null;
|
|
61
|
+
const completionRow = completionById.get(String(id));
|
|
62
|
+
const completion = !row && completionRow !== undefined
|
|
63
|
+
? {
|
|
64
|
+
jobId: id,
|
|
65
|
+
queue: completionRow.queue,
|
|
66
|
+
result: decodePostgresValue(completionRow.result, null, `postgresCompletion:${String(id)}`),
|
|
67
|
+
pinned: false,
|
|
68
|
+
}
|
|
69
|
+
: null;
|
|
70
|
+
return [id, { row, completion }];
|
|
71
|
+
}));
|
|
72
|
+
}
|