bunqueue 2.8.60 → 2.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -78
- package/dist/application/background/dlq.js +2 -0
- package/dist/application/background/recovery/active.d.ts +1 -0
- package/dist/application/background/recovery/active.js +12 -0
- package/dist/application/background/recovery/index.js +3 -1
- package/dist/application/background/recovery/pending.js +1 -0
- package/dist/application/cleanupTasks.js +4 -16
- package/dist/application/contextFactory.js +8 -0
- package/dist/application/dlqManager.d.ts +10 -0
- package/dist/application/dlqManager.js +48 -9
- package/dist/application/dlqRetry.js +60 -38
- package/dist/application/eventsManager.d.ts +9 -2
- package/dist/application/eventsManager.js +106 -55
- package/dist/application/operations/ackHelpers.d.ts +1 -4
- package/dist/application/operations/ackHelpers.js +39 -14
- package/dist/application/operations/flowPush.js +1 -0
- package/dist/application/operations/flowValidation.js +4 -4
- package/dist/application/operations/jobManagement.d.ts +4 -0
- package/dist/application/operations/jobMoveOperations.js +9 -4
- package/dist/application/operations/pull.d.ts +7 -2
- package/dist/application/operations/pull.js +15 -57
- package/dist/application/operations/pullFinalization.d.ts +6 -0
- package/dist/application/operations/pullFinalization.js +69 -0
- package/dist/application/operations/pullStateTransition.d.ts +8 -7
- package/dist/application/operations/pullStateTransition.js +25 -18
- package/dist/application/operations/push.js +3 -0
- package/dist/application/operations/pushBatch.js +14 -7
- package/dist/application/operations/pushContext.d.ts +2 -1
- 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 +30 -0
- package/dist/application/postgres-queue-manager/control.js +210 -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 +20 -0
- package/dist/application/postgres-queue-manager/delivery.js +83 -0
- package/dist/application/postgres-queue-manager/groupQueries.d.ts +10 -0
- package/dist/application/postgres-queue-manager/groupQueries.js +40 -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/control.js +1 -0
- package/dist/application/queue-manager/delivery.d.ts +5 -4
- package/dist/application/queue-manager/delivery.js +15 -8
- package/dist/application/queue-manager/flow-failures.js +4 -0
- package/dist/application/queue-manager/limits.d.ts +13 -0
- package/dist/application/queue-manager/limits.js +65 -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 +17 -2
- package/dist/application/queueTelemetryJournal.d.ts +2 -0
- package/dist/application/queueTelemetryJournal.js +23 -0
- package/dist/application/types/ack.d.ts +3 -1
- package/dist/cli/commandRouter.d.ts +1 -1
- package/dist/cli/commands/server.js +1 -1
- package/dist/client/flowPush.js +6 -0
- package/dist/client/forwarder.d.ts +6 -4
- package/dist/client/forwarder.js +5 -3
- package/dist/client/groupId.d.ts +1 -0
- package/dist/client/groupId.js +1 -0
- package/dist/client/index.d.ts +1 -1
- package/dist/client/jobHelpers.js +1 -0
- 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/bulk.js +4 -4
- package/dist/client/queue/operations/add/payload.d.ts +1 -0
- package/dist/client/queue/operations/add/payload.js +7 -1
- package/dist/client/queue/operations/add/single.js +3 -3
- package/dist/client/queue/operations/groups.d.ts +21 -0
- package/dist/client/queue/operations/groups.js +88 -0
- package/dist/client/queue/runtime/configuration.d.ts +4 -0
- package/dist/client/queue/runtime/configuration.js +8 -0
- package/dist/client/queue/runtime/queries.d.ts +13 -0
- package/dist/client/queue/runtime/queries.js +31 -0
- package/dist/client/queue/runtime/state.d.ts +4 -0
- package/dist/client/queue/runtime/state.js +1 -0
- package/dist/client/types/index.d.ts +2 -2
- package/dist/client/types/options.d.ts +4 -0
- package/dist/client/types/worker.d.ts +8 -0
- package/dist/client/worker/runtime/execution.js +4 -8
- package/dist/client/worker/runtime/options.js +3 -0
- package/dist/client/worker/runtime/polling.d.ts +1 -0
- package/dist/client/worker/runtime/polling.js +9 -0
- package/dist/client/worker/types/options.d.ts +2 -1
- package/dist/client/worker/workerPull.d.ts +2 -0
- package/dist/client/worker/workerPull.js +6 -4
- 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/job/groupFifoOrder.d.ts +9 -0
- package/dist/domain/job/groupFifoOrder.js +26 -0
- package/dist/domain/queue/dlqShard.d.ts +2 -0
- package/dist/domain/queue/dlqShard.js +16 -0
- package/dist/domain/queue/groupLimiterManager.d.ts +23 -0
- package/dist/domain/queue/groupLimiterManager.js +107 -0
- package/dist/domain/queue/groupScheduler.d.ts +31 -0
- package/dist/domain/queue/groupScheduler.js +256 -0
- package/dist/domain/queue/groupSchedulerOrder.d.ts +6 -0
- package/dist/domain/queue/groupSchedulerOrder.js +30 -0
- package/dist/domain/queue/priorityQueue.d.ts +13 -23
- package/dist/domain/queue/priorityQueue.js +53 -42
- package/dist/domain/queue/shard/dlq.d.ts +1 -0
- package/dist/domain/queue/shard/dlq.js +3 -0
- package/dist/domain/queue/shard/keys.d.ts +1 -0
- package/dist/domain/queue/shard/keys.js +25 -2
- package/dist/domain/queue/shard/lifecycle.js +4 -0
- package/dist/domain/queue/shard/limits.d.ts +20 -1
- package/dist/domain/queue/shard/limits.js +56 -0
- package/dist/domain/queue/shard/state.d.ts +5 -0
- package/dist/domain/queue/shard/state.js +9 -1
- package/dist/domain/types/commands/core.d.ts +3 -0
- package/dist/domain/types/commands/dlq.d.ts +5 -0
- package/dist/domain/types/commands/limits.d.ts +41 -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/group.d.ts +21 -0
- package/dist/domain/types/group.js +78 -0
- package/dist/domain/types/jobs/model.d.ts +1 -1
- package/dist/domain/types/priorityQueue.d.ts +1 -0
- 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/jobOptionsBlob.d.ts +1 -0
- package/dist/infrastructure/persistence/jobOptionsBlob.js +10 -2
- package/dist/infrastructure/persistence/migrations.js +11 -0
- package/dist/infrastructure/persistence/postgres/admission.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/admission.js +196 -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 +128 -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 +14 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.js +69 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.js +140 -0
- package/dist/infrastructure/persistence/postgres/claims.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/claims.js +153 -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/eventCatchupCursors.d.ts +32 -0
- package/dist/infrastructure/persistence/postgres/eventCatchupCursors.js +66 -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 +267 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +26 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +129 -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 +276 -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/groupClaims.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/groupClaims.js +95 -0
- package/dist/infrastructure/persistence/postgres/groupSchema.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/groupSchema.js +155 -0
- package/dist/infrastructure/persistence/postgres/groupSchemaFingerprint.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/groupSchemaFingerprint.js +127 -0
- package/dist/infrastructure/persistence/postgres/groupStateRetention.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/groupStateRetention.js +93 -0
- package/dist/infrastructure/persistence/postgres/groups.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/groups.js +117 -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 +158 -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 +45 -0
- package/dist/infrastructure/persistence/postgres/runtime.js +238 -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 +261 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.js +226 -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 +100 -0
- package/dist/infrastructure/persistence/postgres/store.js +180 -0
- package/dist/infrastructure/persistence/postgres/telemetry.d.ts +8 -0
- package/dist/infrastructure/persistence/postgres/telemetry.js +100 -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 +176 -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/schema.d.ts +2 -2
- package/dist/infrastructure/persistence/schema.js +12 -1
- package/dist/infrastructure/persistence/sqlite/control.d.ts +14 -0
- package/dist/infrastructure/persistence/sqlite/control.js +69 -0
- package/dist/infrastructure/persistence/sqlite/jobs.d.ts +12 -0
- package/dist/infrastructure/persistence/sqlite/jobs.js +38 -0
- package/dist/infrastructure/persistence/sqlite/telemetry.d.ts +2 -1
- package/dist/infrastructure/persistence/sqlite/telemetry.js +5 -64
- package/dist/infrastructure/persistence/sqlite/telemetryWrites.d.ts +4 -0
- package/dist/infrastructure/persistence/sqlite/telemetryWrites.js +123 -0
- package/dist/infrastructure/persistence/sqliteSerializer.js +2 -0
- 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 +16 -1
- package/dist/infrastructure/server/handler-routes/monitoring.d.ts +2 -2
- package/dist/infrastructure/server/handler.js +9 -11
- 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.d.ts +0 -5
- package/dist/infrastructure/server/handlers/core.js +47 -49
- 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/groups.d.ts +11 -0
- package/dist/infrastructure/server/handlers/groups.js +55 -0
- 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 +56 -8
- 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 +18 -7
- package/dist/infrastructure/server/httpRouteQueues.js +11 -1
- package/dist/infrastructure/server/protocol/validation.d.ts +1 -0
- package/dist/infrastructure/server/protocol/validation.js +1 -0
- package/dist/infrastructure/server/protocol.d.ts +1 -1
- package/dist/infrastructure/server/protocol.js +1 -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 +75 -65
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { PostgresQueueManagerRelationships } from './relationships';
|
|
2
|
+
function matchesFilter(entry, filter, now) {
|
|
3
|
+
if (filter.reason && entry.reason !== filter.reason)
|
|
4
|
+
return false;
|
|
5
|
+
if (filter.olderThan !== undefined && entry.enteredAt >= filter.olderThan)
|
|
6
|
+
return false;
|
|
7
|
+
if (filter.newerThan !== undefined && entry.enteredAt <= filter.newerThan)
|
|
8
|
+
return false;
|
|
9
|
+
if (filter.expired !== undefined &&
|
|
10
|
+
(entry.expiresAt !== null && entry.expiresAt <= now) !== filter.expired) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
function boundedLimit(value) {
|
|
16
|
+
if (value === undefined)
|
|
17
|
+
return Number.MAX_SAFE_INTEGER;
|
|
18
|
+
return Number.isFinite(value) && value > 0 ? Math.floor(value) : 0;
|
|
19
|
+
}
|
|
20
|
+
/** Durable maintenance commands that cannot use the synchronous SQLite façade. */
|
|
21
|
+
export class PostgresQueueManagerMaintenance extends PostgresQueueManagerRelationships {
|
|
22
|
+
async retryDlqDurable(queue, id, count, filter) {
|
|
23
|
+
return await this.runPostgresOperation(async () => {
|
|
24
|
+
await this.postgresReady;
|
|
25
|
+
const limit = boundedLimit(count ?? filter?.limit);
|
|
26
|
+
if (limit === 0)
|
|
27
|
+
return 0;
|
|
28
|
+
const now = await this.postgresStore.now();
|
|
29
|
+
let entries = await this.postgresStore.getDlq(queue, 2_147_483_647);
|
|
30
|
+
if (id)
|
|
31
|
+
entries = entries.filter((entry) => entry.job.id === id);
|
|
32
|
+
if (filter)
|
|
33
|
+
entries = entries.filter((entry) => matchesFilter(entry, filter, now));
|
|
34
|
+
const offset = Math.max(0, filter?.offset ?? 0);
|
|
35
|
+
entries = entries.slice(offset, offset + limit);
|
|
36
|
+
let retried = 0;
|
|
37
|
+
for (const entry of entries) {
|
|
38
|
+
if (await this.postgresStore.retry(entry.job.id))
|
|
39
|
+
retried++;
|
|
40
|
+
}
|
|
41
|
+
if (retried > 0)
|
|
42
|
+
await this.refreshQueueAfterCommit(queue);
|
|
43
|
+
return retried;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
async purgeDlqDurable(queue) {
|
|
47
|
+
return await this.runPostgresOperation(async () => {
|
|
48
|
+
await this.postgresReady;
|
|
49
|
+
const ids = await this.postgresStore.purgeDlq(queue);
|
|
50
|
+
if (ids.length > 0)
|
|
51
|
+
await this.refreshQueueAfterCommit(queue);
|
|
52
|
+
return ids.length;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async removeDlqJobDurable(queue, id) {
|
|
56
|
+
return await this.runPostgresOperation(async () => {
|
|
57
|
+
await this.postgresReady;
|
|
58
|
+
const removed = await this.postgresStore.removeDlq(queue, id);
|
|
59
|
+
if (removed)
|
|
60
|
+
this.postgresSnapshot.remove(id);
|
|
61
|
+
return removed;
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async retryCompletedDurable(queue, id, options = {}) {
|
|
65
|
+
return await this.runPostgresOperation(async () => {
|
|
66
|
+
await this.postgresReady;
|
|
67
|
+
const limit = boundedLimit(options.limit);
|
|
68
|
+
if (limit === 0)
|
|
69
|
+
return 0;
|
|
70
|
+
let rows = await this.postgresStore.list(queue, {
|
|
71
|
+
states: ['completed'],
|
|
72
|
+
limit: 2_147_483_647,
|
|
73
|
+
asc: true,
|
|
74
|
+
});
|
|
75
|
+
if (id)
|
|
76
|
+
rows = rows.filter((row) => row.job.id === id);
|
|
77
|
+
const timestamp = options.timestamp;
|
|
78
|
+
if (timestamp !== undefined) {
|
|
79
|
+
rows = rows.filter((row) => (row.job.completedAt ?? Infinity) <= timestamp);
|
|
80
|
+
}
|
|
81
|
+
let retried = 0;
|
|
82
|
+
for (const row of rows.slice(0, limit)) {
|
|
83
|
+
if (await this.postgresStore.retry(row.job.id))
|
|
84
|
+
retried++;
|
|
85
|
+
}
|
|
86
|
+
if (retried > 0)
|
|
87
|
+
await this.refreshQueueAfterCommit(queue);
|
|
88
|
+
return retried;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
async cleanDurable(queue, graceMs, state, limit) {
|
|
92
|
+
return await this.runPostgresOperation(async () => {
|
|
93
|
+
await this.postgresReady;
|
|
94
|
+
const ids = await this.postgresStore.clean(queue, graceMs, state, limit);
|
|
95
|
+
if (ids.length > 0)
|
|
96
|
+
await this.refreshQueueAfterCommit(queue);
|
|
97
|
+
return ids;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export type PostgresSyncAdmission<T> = {
|
|
2
|
+
readonly accepted: true;
|
|
3
|
+
readonly value: T;
|
|
4
|
+
} | {
|
|
5
|
+
readonly accepted: false;
|
|
6
|
+
};
|
|
7
|
+
/** Stop new PostgreSQL operations and drain work admitted before shutdown. */
|
|
8
|
+
export declare class PostgresOperationGate {
|
|
9
|
+
private readonly maxConcurrent;
|
|
10
|
+
private readonly maxQueued;
|
|
11
|
+
private readonly scopes;
|
|
12
|
+
private accepting;
|
|
13
|
+
private active;
|
|
14
|
+
private running;
|
|
15
|
+
private readonly queued;
|
|
16
|
+
private drainPromise;
|
|
17
|
+
private resolveDrain;
|
|
18
|
+
constructor(maxConcurrent?: number, maxQueued?: number);
|
|
19
|
+
run<T>(operation: () => Promise<T>): Promise<T>;
|
|
20
|
+
runSync<T>(operation: () => T): T;
|
|
21
|
+
tryRunSync<T>(operation: () => T): PostgresSyncAdmission<T>;
|
|
22
|
+
closeAndDrain(): Promise<void>;
|
|
23
|
+
private admit;
|
|
24
|
+
private enterSync;
|
|
25
|
+
private finish;
|
|
26
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
/** Stop new PostgreSQL operations and drain work admitted before shutdown. */
|
|
3
|
+
export class PostgresOperationGate {
|
|
4
|
+
maxConcurrent;
|
|
5
|
+
maxQueued;
|
|
6
|
+
scopes = new AsyncLocalStorage();
|
|
7
|
+
accepting = true;
|
|
8
|
+
active = 0;
|
|
9
|
+
running = 0;
|
|
10
|
+
queued = [];
|
|
11
|
+
drainPromise = null;
|
|
12
|
+
resolveDrain = null;
|
|
13
|
+
constructor(maxConcurrent = Number.POSITIVE_INFINITY, maxQueued = Number.POSITIVE_INFINITY) {
|
|
14
|
+
this.maxConcurrent = maxConcurrent;
|
|
15
|
+
this.maxQueued = maxQueued;
|
|
16
|
+
}
|
|
17
|
+
async run(operation) {
|
|
18
|
+
const parent = this.scopes.getStore();
|
|
19
|
+
const nested = parent?.active === true;
|
|
20
|
+
await this.admit(nested);
|
|
21
|
+
const scope = { active: true };
|
|
22
|
+
try {
|
|
23
|
+
return await this.scopes.run(scope, operation);
|
|
24
|
+
}
|
|
25
|
+
finally {
|
|
26
|
+
this.finish(scope, nested);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
runSync(operation) {
|
|
30
|
+
const scope = this.enterSync();
|
|
31
|
+
try {
|
|
32
|
+
return this.scopes.run(scope, operation);
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
this.finish(scope, true);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
tryRunSync(operation) {
|
|
39
|
+
if (!this.accepting && !this.scopes.getStore()?.active)
|
|
40
|
+
return { accepted: false };
|
|
41
|
+
return { accepted: true, value: this.runSync(operation) };
|
|
42
|
+
}
|
|
43
|
+
closeAndDrain() {
|
|
44
|
+
if (this.scopes.getStore()?.active) {
|
|
45
|
+
throw new Error('Cannot shut down PostgreSQL from an active queue operation');
|
|
46
|
+
}
|
|
47
|
+
this.accepting = false;
|
|
48
|
+
if (this.active === 0)
|
|
49
|
+
return Promise.resolve();
|
|
50
|
+
this.drainPromise ??= new Promise((resolve) => {
|
|
51
|
+
this.resolveDrain = resolve;
|
|
52
|
+
});
|
|
53
|
+
return this.drainPromise;
|
|
54
|
+
}
|
|
55
|
+
async admit(nested) {
|
|
56
|
+
if (!this.accepting && !this.scopes.getStore()?.active) {
|
|
57
|
+
throw new Error('PostgreSQL queue manager is shutting down');
|
|
58
|
+
}
|
|
59
|
+
if (nested) {
|
|
60
|
+
this.active++;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (this.running < this.maxConcurrent) {
|
|
64
|
+
this.running++;
|
|
65
|
+
this.active++;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (this.queued.length >= this.maxQueued) {
|
|
69
|
+
throw new Error('PostgreSQL operation queue is saturated');
|
|
70
|
+
}
|
|
71
|
+
this.active++;
|
|
72
|
+
await new Promise((resolve) => this.queued.push({ resolve }));
|
|
73
|
+
}
|
|
74
|
+
enterSync() {
|
|
75
|
+
if (!this.accepting && !this.scopes.getStore()?.active) {
|
|
76
|
+
throw new Error('PostgreSQL queue manager is shutting down');
|
|
77
|
+
}
|
|
78
|
+
this.active++;
|
|
79
|
+
return { active: true };
|
|
80
|
+
}
|
|
81
|
+
finish(scope, nested) {
|
|
82
|
+
scope.active = false;
|
|
83
|
+
this.active--;
|
|
84
|
+
if (!nested) {
|
|
85
|
+
const next = this.queued.shift();
|
|
86
|
+
if (next)
|
|
87
|
+
next.resolve();
|
|
88
|
+
else
|
|
89
|
+
this.running--;
|
|
90
|
+
}
|
|
91
|
+
if (this.active !== 0)
|
|
92
|
+
return;
|
|
93
|
+
this.resolveDrain?.();
|
|
94
|
+
this.resolveDrain = null;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { JobId } from '../../domain/types/job';
|
|
2
|
+
import { PostgresQueueManagerCloud } from './cloud';
|
|
3
|
+
export declare class PostgresQueueManagerOperations extends PostgresQueueManagerCloud {
|
|
4
|
+
private readonly clientReleaseSessions;
|
|
5
|
+
cancel(id: JobId): Promise<boolean>;
|
|
6
|
+
updateProgress(id: JobId, progress: number, message?: string): Promise<boolean>;
|
|
7
|
+
updateJobData(id: JobId, data: unknown): Promise<boolean>;
|
|
8
|
+
changePriority(id: JobId, priority: number, lifo?: boolean): Promise<boolean>;
|
|
9
|
+
promote(id: JobId): Promise<boolean>;
|
|
10
|
+
promoteJobs(queue: string, count?: number): Promise<number>;
|
|
11
|
+
moveToDelayed(id: JobId, delay: number, token?: string): Promise<boolean>;
|
|
12
|
+
changeDelay(id: JobId, delay: number, token?: string): Promise<boolean>;
|
|
13
|
+
moveActiveToWait(id: JobId, token?: string): Promise<boolean>;
|
|
14
|
+
changeWaitingDelay(id: JobId, delay: number): Promise<boolean>;
|
|
15
|
+
moveToWaitingChildren(id: JobId, token?: string): Promise<boolean>;
|
|
16
|
+
discard(id: JobId, token?: string): Promise<boolean>;
|
|
17
|
+
getDeduplicationJobId(queue: string, key: string): string | null;
|
|
18
|
+
removeDeduplicationKey(queue: string, key: string): Promise<number>;
|
|
19
|
+
removeJobDeduplicationKey(id: string): Promise<boolean>;
|
|
20
|
+
releaseClientJobs(clientId: string): Promise<number>;
|
|
21
|
+
forceReleaseClientJobs(clientId: string): number;
|
|
22
|
+
private getClientReleaseSession;
|
|
23
|
+
private runClientRelease;
|
|
24
|
+
private releaseClientSession;
|
|
25
|
+
}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { PostgresQueueManagerCloud } from './cloud';
|
|
2
|
+
export class PostgresQueueManagerOperations extends PostgresQueueManagerCloud {
|
|
3
|
+
clientReleaseSessions = new Map();
|
|
4
|
+
async cancel(id) {
|
|
5
|
+
return await this.runPostgresOperation(async () => {
|
|
6
|
+
await this.postgresReady;
|
|
7
|
+
const removed = await this.postgresStore.cancel(id);
|
|
8
|
+
if (removed)
|
|
9
|
+
this.postgresSnapshot.remove(id);
|
|
10
|
+
return removed;
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
async updateProgress(id, progress, message) {
|
|
14
|
+
return await this.runPostgresOperation(async () => {
|
|
15
|
+
await this.postgresReady;
|
|
16
|
+
const updated = await this.postgresStore.updateProgress(id, progress, message);
|
|
17
|
+
if (updated)
|
|
18
|
+
await this.refreshJob(id);
|
|
19
|
+
return updated;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
async updateJobData(id, data) {
|
|
23
|
+
return await this.runPostgresOperation(async () => {
|
|
24
|
+
await this.postgresReady;
|
|
25
|
+
const updated = await this.postgresStore.updateData(id, data);
|
|
26
|
+
if (updated)
|
|
27
|
+
await this.refreshJob(id);
|
|
28
|
+
return updated;
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
async changePriority(id, priority, lifo) {
|
|
32
|
+
return await this.runPostgresOperation(async () => {
|
|
33
|
+
await this.postgresReady;
|
|
34
|
+
const updated = await this.postgresStore.changePriority(id, priority, lifo);
|
|
35
|
+
if (updated)
|
|
36
|
+
await this.refreshJob(id);
|
|
37
|
+
return updated;
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
async promote(id) {
|
|
41
|
+
return await this.runPostgresOperation(async () => {
|
|
42
|
+
await this.postgresReady;
|
|
43
|
+
const promoted = await this.postgresStore.promote(id);
|
|
44
|
+
if (promoted)
|
|
45
|
+
await this.refreshJob(id);
|
|
46
|
+
return promoted;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async promoteJobs(queue, count) {
|
|
50
|
+
return await this.runPostgresOperation(async () => {
|
|
51
|
+
await this.postgresReady;
|
|
52
|
+
const promoted = await this.postgresStore.promoteMany(queue, count);
|
|
53
|
+
if (promoted.length > 0)
|
|
54
|
+
await this.refreshQueueAfterCommit(queue);
|
|
55
|
+
return promoted.length;
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
async moveToDelayed(id, delay, token) {
|
|
59
|
+
return await this.runPostgresOperation(() => this.changeDelay(id, delay, token));
|
|
60
|
+
}
|
|
61
|
+
async changeDelay(id, delay, token) {
|
|
62
|
+
return await this.runPostgresOperation(async () => {
|
|
63
|
+
await this.postgresReady;
|
|
64
|
+
const now = await this.postgresStore.now();
|
|
65
|
+
const changed = await this.postgresStore.changeDelay(id, now + Math.max(0, delay), this.tokenFor(id, token) ?? undefined);
|
|
66
|
+
if (changed) {
|
|
67
|
+
this.forgetToken(id);
|
|
68
|
+
await this.refreshJob(id);
|
|
69
|
+
}
|
|
70
|
+
return changed;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
async moveActiveToWait(id, token) {
|
|
74
|
+
return await this.runPostgresOperation(async () => {
|
|
75
|
+
await this.postgresReady;
|
|
76
|
+
const now = await this.postgresStore.now();
|
|
77
|
+
const moved = await this.postgresStore.changeDelay(id, now, this.tokenFor(id, token) ?? undefined);
|
|
78
|
+
if (moved) {
|
|
79
|
+
this.forgetToken(id);
|
|
80
|
+
await this.refreshJob(id);
|
|
81
|
+
}
|
|
82
|
+
return moved;
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
async changeWaitingDelay(id, delay) {
|
|
86
|
+
return await this.runPostgresOperation(() => this.changeDelay(id, delay));
|
|
87
|
+
}
|
|
88
|
+
async moveToWaitingChildren(id, token) {
|
|
89
|
+
return await this.runPostgresOperation(async () => {
|
|
90
|
+
await this.postgresReady;
|
|
91
|
+
const moved = await this.postgresStore.moveToWaitingChildren(id, this.tokenFor(id, token) ?? undefined);
|
|
92
|
+
if (moved) {
|
|
93
|
+
this.forgetToken(id);
|
|
94
|
+
await this.refreshJob(id);
|
|
95
|
+
}
|
|
96
|
+
return moved;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
async discard(id, token) {
|
|
100
|
+
return await this.runPostgresOperation(async () => {
|
|
101
|
+
await this.postgresReady;
|
|
102
|
+
const removed = await this.postgresStore.discard(id, this.tokenFor(id, token) ?? undefined);
|
|
103
|
+
if (removed) {
|
|
104
|
+
this.forgetToken(id);
|
|
105
|
+
await this.refreshJob(id);
|
|
106
|
+
}
|
|
107
|
+
return removed;
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
getDeduplicationJobId(queue, key) {
|
|
111
|
+
return this.postgresSnapshot.getByUniqueKey(queue, key)?.id ?? null;
|
|
112
|
+
}
|
|
113
|
+
async removeDeduplicationKey(queue, key) {
|
|
114
|
+
return await this.runPostgresOperation(async () => {
|
|
115
|
+
const job = this.postgresSnapshot.getByUniqueKey(queue, key);
|
|
116
|
+
if (!job)
|
|
117
|
+
return 0;
|
|
118
|
+
const removed = await this.postgresStore.clearUniqueKey(job.id);
|
|
119
|
+
if (removed)
|
|
120
|
+
await this.refreshJob(job.id);
|
|
121
|
+
return removed ? 1 : 0;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
async removeJobDeduplicationKey(id) {
|
|
125
|
+
return await this.runPostgresOperation(async () => {
|
|
126
|
+
await this.postgresReady;
|
|
127
|
+
const removed = await this.postgresStore.clearUniqueKey(id);
|
|
128
|
+
if (removed)
|
|
129
|
+
await this.refreshJob(id);
|
|
130
|
+
return removed;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
async releaseClientJobs(clientId) {
|
|
134
|
+
return await this.runPostgresOperation(() => this.runClientRelease(clientId));
|
|
135
|
+
}
|
|
136
|
+
forceReleaseClientJobs(clientId) {
|
|
137
|
+
const admitted = this.operations.tryRunSync(() => {
|
|
138
|
+
const session = this.getClientReleaseSession(clientId);
|
|
139
|
+
const tracked = session.leases.size;
|
|
140
|
+
if (tracked > 0)
|
|
141
|
+
this.enqueueWrite(() => this.runClientRelease(clientId).then(() => undefined));
|
|
142
|
+
return tracked;
|
|
143
|
+
});
|
|
144
|
+
if (admitted.accepted)
|
|
145
|
+
return admitted.value;
|
|
146
|
+
return this.clientReleaseSessions.get(clientId)?.leases.size ?? 0;
|
|
147
|
+
}
|
|
148
|
+
getClientReleaseSession(clientId) {
|
|
149
|
+
const current = this.clientReleaseSessions.get(clientId);
|
|
150
|
+
if (current)
|
|
151
|
+
return current;
|
|
152
|
+
const leases = new Map();
|
|
153
|
+
for (const id of this.clientJobs.get(clientId) ?? []) {
|
|
154
|
+
const token = this.tokenFor(id);
|
|
155
|
+
if (token)
|
|
156
|
+
leases.set(id, token);
|
|
157
|
+
else
|
|
158
|
+
this.clientJobs.get(clientId)?.delete(id);
|
|
159
|
+
}
|
|
160
|
+
if (this.clientJobs.get(clientId)?.size === 0)
|
|
161
|
+
this.clientJobs.delete(clientId);
|
|
162
|
+
const session = { leases, released: 0, inFlight: null };
|
|
163
|
+
this.clientReleaseSessions.set(clientId, session);
|
|
164
|
+
return session;
|
|
165
|
+
}
|
|
166
|
+
async runClientRelease(clientId) {
|
|
167
|
+
const session = this.getClientReleaseSession(clientId);
|
|
168
|
+
if (session.inFlight)
|
|
169
|
+
return await session.inFlight;
|
|
170
|
+
const attempt = this.releaseClientSession(clientId, session).finally(() => {
|
|
171
|
+
if (session.inFlight === attempt)
|
|
172
|
+
session.inFlight = null;
|
|
173
|
+
});
|
|
174
|
+
session.inFlight = attempt;
|
|
175
|
+
return await attempt;
|
|
176
|
+
}
|
|
177
|
+
async releaseClientSession(clientId, session) {
|
|
178
|
+
for (const [id, token] of [...session.leases]) {
|
|
179
|
+
const released = await this.postgresStore.releaseClientLease(id, token);
|
|
180
|
+
session.leases.delete(id);
|
|
181
|
+
this.clientJobs.get(clientId)?.delete(id);
|
|
182
|
+
if (this.clientJobs.get(clientId)?.size === 0)
|
|
183
|
+
this.clientJobs.delete(clientId);
|
|
184
|
+
if (this.activeTokens.get(id) === token)
|
|
185
|
+
this.activeTokens.delete(id);
|
|
186
|
+
if (released)
|
|
187
|
+
session.released++;
|
|
188
|
+
await this.refreshJob(id);
|
|
189
|
+
}
|
|
190
|
+
if (session.leases.size === 0)
|
|
191
|
+
this.clientReleaseSessions.delete(clientId);
|
|
192
|
+
return session.released;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { JobId } from '../../domain/types/job';
|
|
2
|
+
import type { PostgresJobProjection } from '../../infrastructure/persistence/postgres/readModels';
|
|
3
|
+
import type { PostgresQueueSnapshot } from './snapshot';
|
|
4
|
+
export type { PostgresJobProjection } from '../../infrastructure/persistence/postgres/readModels';
|
|
5
|
+
export declare function applyPostgresJobProjection(snapshot: PostgresQueueSnapshot, activeTokens: Map<JobId, string>, id: JobId, projection: PostgresJobProjection): void;
|
|
6
|
+
type ProjectionLoader = (requests: readonly {
|
|
7
|
+
id: JobId;
|
|
8
|
+
queue: string;
|
|
9
|
+
}[]) => Promise<ReadonlyMap<JobId, PostgresJobProjection>>;
|
|
10
|
+
type ProjectionApplier = (id: JobId, projection: PostgresJobProjection) => void;
|
|
11
|
+
type ProjectionReporter = (queue: string, id: JobId, error: unknown) => void;
|
|
12
|
+
/** Coalesced, generation-fenced repair of the local PostgreSQL read model. */
|
|
13
|
+
export declare class PostgresProjectionRefreshes {
|
|
14
|
+
private readonly load;
|
|
15
|
+
private readonly apply;
|
|
16
|
+
private readonly report;
|
|
17
|
+
private readonly retryDelayMs;
|
|
18
|
+
private static readonly MAX_ACTIVE_BATCHES;
|
|
19
|
+
private static readonly MAX_REQUESTS_PER_BATCH;
|
|
20
|
+
private readonly generations;
|
|
21
|
+
private readonly generationQueues;
|
|
22
|
+
private readonly pending;
|
|
23
|
+
private readonly active;
|
|
24
|
+
private timer;
|
|
25
|
+
private accepting;
|
|
26
|
+
private started;
|
|
27
|
+
constructor(load: ProjectionLoader, apply: ProjectionApplier, report: ProjectionReporter, retryDelayMs: number);
|
|
28
|
+
request(id: JobId, queue: string): void;
|
|
29
|
+
supersede(id: JobId): void;
|
|
30
|
+
supersedeQueue(queue: string): void;
|
|
31
|
+
refreshNow(id: JobId, queue: string): Promise<PostgresJobProjection>;
|
|
32
|
+
refreshManyNow(requests: readonly {
|
|
33
|
+
id: JobId;
|
|
34
|
+
queue: string;
|
|
35
|
+
}[]): Promise<ReadonlyMap<JobId, PostgresJobProjection>>;
|
|
36
|
+
start(): void;
|
|
37
|
+
close(): void;
|
|
38
|
+
drain(): Promise<void>;
|
|
39
|
+
private schedule;
|
|
40
|
+
private runBatch;
|
|
41
|
+
private beginGeneration;
|
|
42
|
+
private endGeneration;
|
|
43
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
export function applyPostgresJobProjection(snapshot, activeTokens, id, projection) {
|
|
2
|
+
snapshot.reconcile(id, projection.row, projection.completion);
|
|
3
|
+
const token = activeTokens.get(id);
|
|
4
|
+
if (token && (projection.row?.state !== 'active' || projection.row.token !== token)) {
|
|
5
|
+
activeTokens.delete(id);
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
/** Coalesced, generation-fenced repair of the local PostgreSQL read model. */
|
|
9
|
+
export class PostgresProjectionRefreshes {
|
|
10
|
+
load;
|
|
11
|
+
apply;
|
|
12
|
+
report;
|
|
13
|
+
retryDelayMs;
|
|
14
|
+
static MAX_ACTIVE_BATCHES = 2;
|
|
15
|
+
static MAX_REQUESTS_PER_BATCH = 1_000;
|
|
16
|
+
generations = new Map();
|
|
17
|
+
generationQueues = new Map();
|
|
18
|
+
pending = new Map();
|
|
19
|
+
active = new Set();
|
|
20
|
+
timer = null;
|
|
21
|
+
accepting = true;
|
|
22
|
+
started = false;
|
|
23
|
+
constructor(load, apply, report, retryDelayMs) {
|
|
24
|
+
this.load = load;
|
|
25
|
+
this.apply = apply;
|
|
26
|
+
this.report = report;
|
|
27
|
+
this.retryDelayMs = retryDelayMs;
|
|
28
|
+
}
|
|
29
|
+
request(id, queue) {
|
|
30
|
+
if (!this.accepting)
|
|
31
|
+
return;
|
|
32
|
+
const generation = this.beginGeneration(id, queue);
|
|
33
|
+
this.pending.set(id, { queue, generation });
|
|
34
|
+
this.schedule(0);
|
|
35
|
+
}
|
|
36
|
+
supersede(id) {
|
|
37
|
+
this.pending.delete(id);
|
|
38
|
+
this.generations.delete(id);
|
|
39
|
+
this.generationQueues.delete(id);
|
|
40
|
+
}
|
|
41
|
+
supersedeQueue(queue) {
|
|
42
|
+
for (const [id, generationQueue] of this.generationQueues) {
|
|
43
|
+
if (generationQueue === queue)
|
|
44
|
+
this.supersede(id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async refreshNow(id, queue) {
|
|
48
|
+
const projections = await this.refreshManyNow([{ id, queue }]);
|
|
49
|
+
return projections.get(id) ?? { row: null, completion: null };
|
|
50
|
+
}
|
|
51
|
+
async refreshManyNow(requests) {
|
|
52
|
+
let remaining = [...requests];
|
|
53
|
+
const loaded = new Map();
|
|
54
|
+
for (let attempt = 0; attempt < 2 && remaining.length > 0; attempt++) {
|
|
55
|
+
const generations = new Map();
|
|
56
|
+
for (const { id, queue } of remaining) {
|
|
57
|
+
const generation = this.beginGeneration(id, queue);
|
|
58
|
+
this.pending.delete(id);
|
|
59
|
+
generations.set(id, generation);
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const projections = await this.load(remaining);
|
|
63
|
+
const invalidated = [];
|
|
64
|
+
for (const request of remaining) {
|
|
65
|
+
const projection = projections.get(request.id) ?? { row: null, completion: null };
|
|
66
|
+
loaded.set(request.id, projection);
|
|
67
|
+
if (this.generations.get(request.id) !== generations.get(request.id)) {
|
|
68
|
+
invalidated.push(request);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
this.apply(request.id, projection);
|
|
72
|
+
this.report(request.queue, request.id, null);
|
|
73
|
+
this.endGeneration(request.id, generations.get(request.id));
|
|
74
|
+
}
|
|
75
|
+
remaining = invalidated;
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
for (const { id, queue } of remaining) {
|
|
79
|
+
const generation = generations.get(id);
|
|
80
|
+
if (this.generations.get(id) === generation) {
|
|
81
|
+
this.report(queue, id, error);
|
|
82
|
+
this.endGeneration(id, generation);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const { id, queue } of remaining)
|
|
89
|
+
this.request(id, queue);
|
|
90
|
+
return loaded;
|
|
91
|
+
}
|
|
92
|
+
start() {
|
|
93
|
+
if (!this.accepting || this.started)
|
|
94
|
+
return;
|
|
95
|
+
this.started = true;
|
|
96
|
+
this.schedule(0);
|
|
97
|
+
}
|
|
98
|
+
close() {
|
|
99
|
+
this.accepting = false;
|
|
100
|
+
this.pending.clear();
|
|
101
|
+
this.generations.clear();
|
|
102
|
+
this.generationQueues.clear();
|
|
103
|
+
if (this.timer)
|
|
104
|
+
clearTimeout(this.timer);
|
|
105
|
+
this.timer = null;
|
|
106
|
+
}
|
|
107
|
+
async drain() {
|
|
108
|
+
await Promise.all([...this.active]);
|
|
109
|
+
}
|
|
110
|
+
schedule(delayMs) {
|
|
111
|
+
if (!this.accepting ||
|
|
112
|
+
!this.started ||
|
|
113
|
+
this.timer ||
|
|
114
|
+
this.active.size >= PostgresProjectionRefreshes.MAX_ACTIVE_BATCHES ||
|
|
115
|
+
this.pending.size === 0) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
this.timer = setTimeout(() => {
|
|
119
|
+
this.timer = null;
|
|
120
|
+
const execution = this.runBatch();
|
|
121
|
+
this.active.add(execution);
|
|
122
|
+
void execution.then((retry) => {
|
|
123
|
+
this.active.delete(execution);
|
|
124
|
+
this.schedule(retry ? this.retryDelayMs : 0);
|
|
125
|
+
});
|
|
126
|
+
}, delayMs);
|
|
127
|
+
}
|
|
128
|
+
async runBatch() {
|
|
129
|
+
const batch = [...this.pending.entries()].slice(0, PostgresProjectionRefreshes.MAX_REQUESTS_PER_BATCH);
|
|
130
|
+
for (const [id] of batch)
|
|
131
|
+
this.pending.delete(id);
|
|
132
|
+
if (batch.length === 0)
|
|
133
|
+
return false;
|
|
134
|
+
try {
|
|
135
|
+
const projections = await this.load(batch.map(([id, { queue }]) => ({ id, queue })));
|
|
136
|
+
for (const [id, request] of batch) {
|
|
137
|
+
if (this.generations.get(id) !== request.generation)
|
|
138
|
+
continue;
|
|
139
|
+
this.apply(id, projections.get(id) ?? { row: null, completion: null });
|
|
140
|
+
this.report(request.queue, id, null);
|
|
141
|
+
this.endGeneration(id, request.generation);
|
|
142
|
+
}
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
for (const [id, request] of batch) {
|
|
147
|
+
if (this.generations.get(id) === request.generation && this.accepting) {
|
|
148
|
+
this.pending.set(id, request);
|
|
149
|
+
this.report(request.queue, id, error);
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
this.endGeneration(id, request.generation);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return true;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
beginGeneration(id, queue) {
|
|
159
|
+
const generation = Symbol();
|
|
160
|
+
this.generations.set(id, generation);
|
|
161
|
+
this.generationQueues.set(id, queue);
|
|
162
|
+
return generation;
|
|
163
|
+
}
|
|
164
|
+
endGeneration(id, generation) {
|
|
165
|
+
if (generation && this.generations.get(id) === generation && !this.pending.has(id)) {
|
|
166
|
+
this.generations.delete(id);
|
|
167
|
+
this.generationQueues.delete(id);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|