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
|
@@ -7,6 +7,7 @@ import { hostname, arch, platform, cpus } from 'os';
|
|
|
7
7
|
import { throughputTracker } from '../../application/throughputTracker';
|
|
8
8
|
import { latencyTracker } from '../../application/latencyTracker';
|
|
9
9
|
import { VERSION } from '../../shared/version';
|
|
10
|
+
import { clientStorageStatus } from '../../shared/storageHealth';
|
|
10
11
|
/** Cached hostname — computed once */
|
|
11
12
|
const HOST = hostname();
|
|
12
13
|
/** Cached runtime info — computed once */
|
|
@@ -22,7 +23,7 @@ export function buildStatsRefresh(qm) {
|
|
|
22
23
|
const rates = throughputTracker.getRates();
|
|
23
24
|
const percentiles = latencyTracker.getPercentiles();
|
|
24
25
|
const averages = latencyTracker.getAverages();
|
|
25
|
-
const storage = qm.getStorageStatus();
|
|
26
|
+
const storage = clientStorageStatus(qm.getStorageStatus());
|
|
26
27
|
const mem = process.memoryUsage();
|
|
27
28
|
const workerStats = qm.workerManager.getStats();
|
|
28
29
|
const queueNames = qm.listQueues();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { CloudQueueAdapter } from '../queueAdapter/types';
|
|
2
2
|
import type { CloudSnapshot } from './snapshot';
|
|
3
3
|
/** Incoming command from the dashboard. */
|
|
4
4
|
export interface CloudCommand {
|
|
@@ -41,4 +41,4 @@ export interface CommandContext {
|
|
|
41
41
|
getSnapshot?: () => Promise<CloudSnapshot>;
|
|
42
42
|
triggerBackup?: () => Promise<unknown>;
|
|
43
43
|
}
|
|
44
|
-
export type CloudCommandHandler = (
|
|
44
|
+
export type CloudCommandHandler = (adapter: CloudQueueAdapter, command: CloudCommand, context?: CommandContext) => unknown;
|
|
@@ -11,6 +11,7 @@ export interface StoredJobOptions {
|
|
|
11
11
|
debounceId: string | null;
|
|
12
12
|
debounceTtl: number | null;
|
|
13
13
|
durable: boolean;
|
|
14
|
+
groupFifoOrder: string | null;
|
|
14
15
|
}
|
|
15
16
|
/** Persist generation policies that do not have dedicated legacy columns. */
|
|
16
17
|
export declare function encodeJobOptions(job: Job): Uint8Array;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { getGroupFifoOrder } from '../../domain/job/groupFifoOrder';
|
|
1
2
|
import { storageLog } from '../../shared/logger';
|
|
2
3
|
import { decodeMessagePack, encodeMessagePack } from '../../shared/msgpack';
|
|
3
4
|
const DEFAULTS = {
|
|
@@ -12,10 +13,14 @@ const DEFAULTS = {
|
|
|
12
13
|
debounceId: null,
|
|
13
14
|
debounceTtl: null,
|
|
14
15
|
durable: false,
|
|
16
|
+
groupFifoOrder: null,
|
|
15
17
|
};
|
|
18
|
+
function validStoredOrder(value) {
|
|
19
|
+
return typeof value === 'string' && /^[1-9]\d*$/.test(value) ? value : null;
|
|
20
|
+
}
|
|
16
21
|
/** Persist generation policies that do not have dedicated legacy columns. */
|
|
17
22
|
export function encodeJobOptions(job) {
|
|
18
|
-
|
|
23
|
+
const options = {
|
|
19
24
|
backoffConfig: job.backoffConfig,
|
|
20
25
|
repeat: job.repeat,
|
|
21
26
|
stackTraceLimit: job.stackTraceLimit,
|
|
@@ -27,7 +32,9 @@ export function encodeJobOptions(job) {
|
|
|
27
32
|
debounceId: job.debounceId,
|
|
28
33
|
debounceTtl: job.debounceTtl,
|
|
29
34
|
durable: job.durable ?? false,
|
|
30
|
-
}
|
|
35
|
+
};
|
|
36
|
+
const order = getGroupFifoOrder(job);
|
|
37
|
+
return encodeMessagePack(order === null ? options : { ...options, groupFifoOrder: String(order) });
|
|
31
38
|
}
|
|
32
39
|
/** Decode current blobs while giving pre-v34 rows their historical defaults. */
|
|
33
40
|
export function decodeJobOptions(blob, context) {
|
|
@@ -47,6 +54,7 @@ export function decodeJobOptions(blob, context) {
|
|
|
47
54
|
debounceId: decoded.debounceId ?? null,
|
|
48
55
|
debounceTtl: decoded.debounceTtl ?? null,
|
|
49
56
|
durable: decoded.durable ?? false,
|
|
57
|
+
groupFifoOrder: validStoredOrder(decoded.groupFifoOrder),
|
|
50
58
|
};
|
|
51
59
|
}
|
|
52
60
|
catch (error) {
|
|
@@ -117,4 +117,15 @@ CREATE INDEX IF NOT EXISTS idx_queue_metric_buckets_window
|
|
|
117
117
|
`,
|
|
118
118
|
// Persist repeat-chain and advanced per-generation job policies.
|
|
119
119
|
34: 'ALTER TABLE jobs ADD COLUMN extended_options BLOB;',
|
|
120
|
+
// Persist per-group rate and concurrency overrides.
|
|
121
|
+
35: `
|
|
122
|
+
CREATE TABLE IF NOT EXISTS group_state (
|
|
123
|
+
queue TEXT NOT NULL,
|
|
124
|
+
group_id TEXT NOT NULL,
|
|
125
|
+
rate_limit INTEGER,
|
|
126
|
+
rate_duration INTEGER,
|
|
127
|
+
concurrency_limit INTEGER,
|
|
128
|
+
PRIMARY KEY (queue, group_id)
|
|
129
|
+
);
|
|
130
|
+
`,
|
|
120
131
|
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { TransactionSQL } from 'bun';
|
|
2
|
+
import { type Job, type JobId } from '../../../domain/types/job';
|
|
3
|
+
import { type PostgresContext } from './context';
|
|
4
|
+
import type { PostgresAdmissionResult } from './admissionResult';
|
|
5
|
+
export interface AdmitPostgresJobOptions {
|
|
6
|
+
readonly rejectExisting?: boolean;
|
|
7
|
+
readonly linkParent?: boolean;
|
|
8
|
+
readonly dependencyLocksHeld?: boolean;
|
|
9
|
+
readonly queueLifecycleLocksHeld?: boolean;
|
|
10
|
+
readonly dependencyExistenceCheckDeferred?: boolean;
|
|
11
|
+
readonly completionConsumerExemptions?: readonly JobId[];
|
|
12
|
+
/** Flow caller already holds identity locks and batches completion, queue, and event writes. */
|
|
13
|
+
readonly preparedFlow?: {
|
|
14
|
+
readonly now: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/** Insert one job inside the caller's transaction and return its authoritative generation. */
|
|
18
|
+
export declare function admitPostgresJob(tx: TransactionSQL, ctx: PostgresContext, job: Job, options?: AdmitPostgresJobOptions): Promise<PostgresAdmissionResult>;
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { MAX_TIMELINE_ENTRIES } from '../../../domain/types/job';
|
|
2
|
+
import { decodePostgresJob, encodePostgresValue, postgresStateForJob } from './codec';
|
|
3
|
+
import { databaseNow, recordPostgresEvent } from './context';
|
|
4
|
+
import { clearPostgresDeduplication, extendPostgresDeduplication, recordPostgresDeduplicationRemoval, } from './deduplication';
|
|
5
|
+
import { updatePostgresJobParentInTransaction } from './relationships';
|
|
6
|
+
import { assertPostgresDependenciesExist, lockPostgresDependencyCompletions, postgresDependenciesSatisfied, tryLockPostgresDependencyCompletions, } from './dependencyPromotion';
|
|
7
|
+
import { assertNoLivePostgresCompletionConsumers, retirePostgresCompletionGenerations, } from './completionLifecycle';
|
|
8
|
+
import { lockPostgresAdmissionKeys } from './batchAdmission';
|
|
9
|
+
import { linkedPostgresParentQueue, lockPostgresAdmissionParent } from './admissionParent';
|
|
10
|
+
import { lockPostgresAdmissionQueues, registerPostgresAdmissionQueues } from './queueLifecycle';
|
|
11
|
+
function isLive(state) {
|
|
12
|
+
return ['waiting', 'prioritized', 'delayed', 'waiting-children', 'active'].includes(state);
|
|
13
|
+
}
|
|
14
|
+
async function findById(tx, ctx, id) {
|
|
15
|
+
const rows = await tx `
|
|
16
|
+
SELECT * FROM bunqueue_jobs
|
|
17
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${id}
|
|
18
|
+
FOR UPDATE
|
|
19
|
+
`;
|
|
20
|
+
return rows[0] ? decodePostgresJob(rows[0]) : null;
|
|
21
|
+
}
|
|
22
|
+
async function findByUniqueKey(tx, ctx, job) {
|
|
23
|
+
if (!job.uniqueKey)
|
|
24
|
+
return null;
|
|
25
|
+
const rows = await tx `
|
|
26
|
+
SELECT * FROM bunqueue_jobs
|
|
27
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
28
|
+
AND queue = ${job.queue}
|
|
29
|
+
AND unique_key = ${job.uniqueKey}
|
|
30
|
+
AND state IN ('waiting', 'prioritized', 'delayed', 'waiting-children', 'active')
|
|
31
|
+
ORDER BY created_at, id
|
|
32
|
+
LIMIT 1
|
|
33
|
+
FOR UPDATE
|
|
34
|
+
`;
|
|
35
|
+
return rows[0] ?? null;
|
|
36
|
+
}
|
|
37
|
+
async function deleteTerminalGeneration(tx, ctx, id) {
|
|
38
|
+
await tx `
|
|
39
|
+
DELETE FROM bunqueue_job_logs
|
|
40
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ${id}
|
|
41
|
+
`;
|
|
42
|
+
await tx `
|
|
43
|
+
DELETE FROM bunqueue_repeat_links
|
|
44
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
45
|
+
AND (original_id = ${id} OR successor_id = ${id})
|
|
46
|
+
`;
|
|
47
|
+
await tx `
|
|
48
|
+
DELETE FROM bunqueue_flow_failures
|
|
49
|
+
WHERE namespace = ${ctx.config.namespace} AND parent_id = ${id}
|
|
50
|
+
`;
|
|
51
|
+
await tx `
|
|
52
|
+
DELETE FROM bunqueue_dependencies
|
|
53
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ${id}
|
|
54
|
+
`;
|
|
55
|
+
await tx `
|
|
56
|
+
DELETE FROM bunqueue_completions
|
|
57
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ${id}
|
|
58
|
+
`;
|
|
59
|
+
await tx `
|
|
60
|
+
DELETE FROM bunqueue_jobs
|
|
61
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${id}
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
async function insertDependencies(tx, ctx, job) {
|
|
65
|
+
for (const dependencyId of new Set(job.dependsOn.map(String))) {
|
|
66
|
+
await tx `
|
|
67
|
+
INSERT INTO bunqueue_dependencies (namespace, job_id, dependency_id)
|
|
68
|
+
VALUES (${ctx.config.namespace}, ${String(job.id)}, ${dependencyId})
|
|
69
|
+
ON CONFLICT DO NOTHING
|
|
70
|
+
`;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
async function insertRow(tx, ctx, job, state, now) {
|
|
74
|
+
await tx `
|
|
75
|
+
INSERT INTO bunqueue_jobs (
|
|
76
|
+
namespace, id, queue, payload, state, priority, lifo, run_at, created_at,
|
|
77
|
+
started_at, completed_at, attempts, max_attempts, ttl, timeout, unique_key,
|
|
78
|
+
unique_expires_at, custom_id, group_id, group_order, parent_id
|
|
79
|
+
) VALUES (
|
|
80
|
+
${ctx.config.namespace}, ${String(job.id)}, ${job.queue}, ${encodePostgresValue(job)},
|
|
81
|
+
${state}, ${job.priority}, ${job.lifo}, ${job.runAt}, ${job.createdAt},
|
|
82
|
+
${job.startedAt}, ${job.completedAt}, ${job.attempts}, ${job.maxAttempts}, ${job.ttl},
|
|
83
|
+
${job.timeout}, ${job.uniqueKey},
|
|
84
|
+
${job.uniqueKey && job.deduplicationTtl !== null ? now + job.deduplicationTtl : null},
|
|
85
|
+
${job.customId}, ${job.groupId},
|
|
86
|
+
CASE WHEN CAST(${job.groupId} AS TEXT) IS NULL
|
|
87
|
+
THEN NULL ELSE nextval('bunqueue_group_order_seq') END,
|
|
88
|
+
${job.parentId}
|
|
89
|
+
)
|
|
90
|
+
`;
|
|
91
|
+
await insertDependencies(tx, ctx, job);
|
|
92
|
+
}
|
|
93
|
+
/** Insert one job inside the caller's transaction and return its authoritative generation. */
|
|
94
|
+
export async function admitPostgresJob(tx, ctx, job, options = {}) {
|
|
95
|
+
const parentQueue = options.linkParent === false ? null : linkedPostgresParentQueue(job);
|
|
96
|
+
if (!options.queueLifecycleLocksHeld) {
|
|
97
|
+
await lockPostgresAdmissionQueues(tx, ctx, [job.queue]);
|
|
98
|
+
}
|
|
99
|
+
if (!options.dependencyLocksHeld) {
|
|
100
|
+
await lockPostgresDependencyCompletions(tx, ctx, [job.id, ...job.dependsOn]);
|
|
101
|
+
}
|
|
102
|
+
if (parentQueue)
|
|
103
|
+
await lockPostgresAdmissionParent(tx, ctx, job, parentQueue);
|
|
104
|
+
if (!options.preparedFlow)
|
|
105
|
+
await lockPostgresAdmissionKeys(tx, ctx, [job]);
|
|
106
|
+
const now = options.preparedFlow?.now ?? (await databaseNow(tx));
|
|
107
|
+
const existingById = await findById(tx, ctx, String(job.id));
|
|
108
|
+
if (existingById) {
|
|
109
|
+
if (options.rejectExisting)
|
|
110
|
+
throw new Error(`Flow job ${String(job.id)} already exists`);
|
|
111
|
+
if (isLive(existingById.state)) {
|
|
112
|
+
return { job: existingById.job, inserted: false, state: existingById.state };
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
let existingByKeyRow = await findByUniqueKey(tx, ctx, job);
|
|
116
|
+
if (existingByKeyRow &&
|
|
117
|
+
existingByKeyRow.unique_expires_at !== null &&
|
|
118
|
+
Number(existingByKeyRow.unique_expires_at) <= now) {
|
|
119
|
+
await clearPostgresDeduplication(tx, ctx, existingByKeyRow, now);
|
|
120
|
+
existingByKeyRow = null;
|
|
121
|
+
}
|
|
122
|
+
if (existingByKeyRow) {
|
|
123
|
+
let existingByKey = decodePostgresJob(existingByKeyRow);
|
|
124
|
+
if (job.deduplicationReplace) {
|
|
125
|
+
if (existingByKeyRow.state === 'active') {
|
|
126
|
+
await clearPostgresDeduplication(tx, ctx, existingByKeyRow, now);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
const acquired = await tryLockPostgresDependencyCompletions(tx, ctx, [
|
|
130
|
+
existingByKey.job.id,
|
|
131
|
+
]);
|
|
132
|
+
if (!acquired) {
|
|
133
|
+
await recordPostgresEvent(tx, ctx, {
|
|
134
|
+
queue: existingByKey.job.queue,
|
|
135
|
+
type: 'duplicated',
|
|
136
|
+
jobId: existingByKey.job.id,
|
|
137
|
+
occurredAt: now,
|
|
138
|
+
job: existingByKey.job,
|
|
139
|
+
state: existingByKey.state,
|
|
140
|
+
});
|
|
141
|
+
return { job: existingByKey.job, inserted: false, state: existingByKey.state };
|
|
142
|
+
}
|
|
143
|
+
await assertNoLivePostgresCompletionConsumers(tx, ctx, [existingByKey.job.id]);
|
|
144
|
+
await deleteTerminalGeneration(tx, ctx, existingByKeyRow.id);
|
|
145
|
+
await recordPostgresDeduplicationRemoval(tx, ctx, existingByKeyRow, now);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
if (job.deduplicationExtend && job.deduplicationTtl !== null) {
|
|
150
|
+
existingByKey = await extendPostgresDeduplication(tx, ctx, existingByKeyRow, job.deduplicationTtl, now);
|
|
151
|
+
}
|
|
152
|
+
await recordPostgresEvent(tx, ctx, {
|
|
153
|
+
queue: existingByKey.job.queue,
|
|
154
|
+
type: 'duplicated',
|
|
155
|
+
jobId: existingByKey.job.id,
|
|
156
|
+
occurredAt: now,
|
|
157
|
+
job: existingByKey.job,
|
|
158
|
+
state: existingByKey.state,
|
|
159
|
+
});
|
|
160
|
+
return { job: existingByKey.job, inserted: false, state: existingByKey.state };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
if (existingById) {
|
|
164
|
+
await assertNoLivePostgresCompletionConsumers(tx, ctx, [job.id], options.completionConsumerExemptions);
|
|
165
|
+
await deleteTerminalGeneration(tx, ctx, String(job.id));
|
|
166
|
+
}
|
|
167
|
+
else if (!options.preparedFlow) {
|
|
168
|
+
await retirePostgresCompletionGenerations(tx, ctx, [job.id], options.completionConsumerExemptions);
|
|
169
|
+
}
|
|
170
|
+
if (!options.dependencyExistenceCheckDeferred) {
|
|
171
|
+
await assertPostgresDependenciesExist(tx, ctx, job.dependsOn);
|
|
172
|
+
}
|
|
173
|
+
if (job.runAt === job.createdAt)
|
|
174
|
+
job.runAt = now;
|
|
175
|
+
const state = postgresStateForJob(job, await postgresDependenciesSatisfied(tx, ctx, job.dependsOn), now);
|
|
176
|
+
const timelineIndex = job.timeline.length < MAX_TIMELINE_ENTRIES ? job.timeline.length : undefined;
|
|
177
|
+
if (timelineIndex !== undefined)
|
|
178
|
+
job.timeline.push({ state, timestamp: now });
|
|
179
|
+
await insertRow(tx, ctx, job, state, now);
|
|
180
|
+
if (!options.preparedFlow)
|
|
181
|
+
await registerPostgresAdmissionQueues(tx, ctx, [job.queue]);
|
|
182
|
+
const pushedEventId = options.preparedFlow
|
|
183
|
+
? undefined
|
|
184
|
+
: await recordPostgresEvent(tx, ctx, {
|
|
185
|
+
queue: job.queue,
|
|
186
|
+
type: 'pushed',
|
|
187
|
+
jobId: job.id,
|
|
188
|
+
occurredAt: now,
|
|
189
|
+
job,
|
|
190
|
+
state,
|
|
191
|
+
});
|
|
192
|
+
if (parentQueue && job.parentId) {
|
|
193
|
+
await updatePostgresJobParentInTransaction(tx, ctx, job.id, job.parentId, true);
|
|
194
|
+
}
|
|
195
|
+
return { job, inserted: true, state, pushedEventId, timelineIndex };
|
|
196
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { TransactionSQL } from 'bun';
|
|
2
|
+
import type { Job } from '../../../domain/types/job';
|
|
3
|
+
import type { PostgresContext } from './context';
|
|
4
|
+
export declare function linkedPostgresParentQueue(job: Job): string | null;
|
|
5
|
+
export declare function lockPostgresAdmissionParent(tx: TransactionSQL, ctx: PostgresContext, job: Job, expectedQueue: string): Promise<void>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { lockPostgresFlowParent } from './flowFailures';
|
|
2
|
+
export function linkedPostgresParentQueue(job) {
|
|
3
|
+
if (!job.parentId ||
|
|
4
|
+
typeof job.data !== 'object' ||
|
|
5
|
+
job.data === null ||
|
|
6
|
+
Array.isArray(job.data)) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const data = job.data;
|
|
10
|
+
if (String(data.__parentId) !== String(job.parentId))
|
|
11
|
+
return null;
|
|
12
|
+
return typeof data.__parentQueue === 'string' && data.__parentQueue.length > 0
|
|
13
|
+
? data.__parentQueue
|
|
14
|
+
: null;
|
|
15
|
+
}
|
|
16
|
+
export async function lockPostgresAdmissionParent(tx, ctx, job, expectedQueue) {
|
|
17
|
+
const parentId = job.parentId;
|
|
18
|
+
if (parentId === job.id)
|
|
19
|
+
throw new Error('A job cannot be its own parent');
|
|
20
|
+
await lockPostgresFlowParent(tx, ctx, parentId);
|
|
21
|
+
const rows = await tx `
|
|
22
|
+
SELECT queue, state FROM bunqueue_jobs
|
|
23
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${String(parentId)}
|
|
24
|
+
FOR UPDATE
|
|
25
|
+
`;
|
|
26
|
+
const parent = rows[0];
|
|
27
|
+
if (!parent)
|
|
28
|
+
throw new Error(`Parent job not found: ${String(parentId)}`);
|
|
29
|
+
if (parent.queue !== expectedQueue) {
|
|
30
|
+
throw new Error(`Parent job ${String(parentId)} belongs to queue ${parent.queue}, not ${expectedQueue}`);
|
|
31
|
+
}
|
|
32
|
+
if (['active', 'completed', 'failed'].includes(parent.state)) {
|
|
33
|
+
throw new Error(`Parent job ${String(parentId)} is not linkable`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Job } from '../../../domain/types/job';
|
|
2
|
+
import type { PostgresJobState } from './types';
|
|
3
|
+
export interface PostgresAdmissionResult {
|
|
4
|
+
readonly job: Job;
|
|
5
|
+
readonly inserted: boolean;
|
|
6
|
+
readonly state: PostgresJobState;
|
|
7
|
+
readonly pushedEventId?: number;
|
|
8
|
+
readonly timelineIndex?: number;
|
|
9
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { AtomicFlowBatchInput } from '../../../domain/types/flow';
|
|
2
|
+
import { type Job } from '../../../domain/types/job';
|
|
3
|
+
import { PostgresQueueStoreRuntime } from './runtime';
|
|
4
|
+
/** Atomic single, batch, and flow admission strategy shared by the store facade. */
|
|
5
|
+
export declare class PostgresAdmissionStore extends PostgresQueueStoreRuntime {
|
|
6
|
+
insert(job: Job): Promise<{
|
|
7
|
+
job: Job;
|
|
8
|
+
inserted: boolean;
|
|
9
|
+
}>;
|
|
10
|
+
insertMany(jobs: readonly Job[], rejectExisting?: boolean): Promise<Job[]>;
|
|
11
|
+
insertFlow(batch: AtomicFlowBatchInput): Promise<Job[]>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { validateAtomicFlowBatch } from '../../../application/operations/flowValidation';
|
|
2
|
+
import { createJob } from '../../../domain/types/job';
|
|
3
|
+
import { admitPostgresJob } from './admission';
|
|
4
|
+
import { recordPostgresJobEvents } from './batchEvents';
|
|
5
|
+
import { admitPostgresJobsBatch, canBatchAdmitPostgresJobs, lockPostgresAdmissionKeys, PostgresBatchAdmissionConflict, } from './batchAdmission';
|
|
6
|
+
import { retirePostgresCompletionGenerations } from './completionLifecycle';
|
|
7
|
+
import { databaseNow } from './context';
|
|
8
|
+
import { assertPostgresDependenciesExist, lockPostgresDependencyCompletions, } from './dependencyPromotion';
|
|
9
|
+
import { lockPostgresFlowParents } from './flowFailures';
|
|
10
|
+
import { PostgresQueueStoreRuntime } from './runtime';
|
|
11
|
+
import { reconcilePostgresSerialAdmissions } from './serialAdmission';
|
|
12
|
+
import { lockPostgresAdmissionQueues, registerPostgresAdmissionQueues } from './queueLifecycle';
|
|
13
|
+
import { runPostgresTransactionWithRetry } from './transactionRetry';
|
|
14
|
+
function admissionDependencyIds(jobs) {
|
|
15
|
+
return jobs.flatMap((job) => [job.id, ...job.dependsOn]);
|
|
16
|
+
}
|
|
17
|
+
function admissionParentIds(jobs) {
|
|
18
|
+
return jobs.flatMap((job) => (job.parentId ? [job.parentId] : []));
|
|
19
|
+
}
|
|
20
|
+
function replaySafeAdmissionJob(job) {
|
|
21
|
+
return { ...job, timeline: [...job.timeline] };
|
|
22
|
+
}
|
|
23
|
+
/** Atomic single, batch, and flow admission strategy shared by the store facade. */
|
|
24
|
+
export class PostgresAdmissionStore extends PostgresQueueStoreRuntime {
|
|
25
|
+
async insert(job) {
|
|
26
|
+
await this.initialize();
|
|
27
|
+
return await runPostgresTransactionWithRetry(this.context, (tx) => admitPostgresJob(tx, this.context, replaySafeAdmissionJob(job)));
|
|
28
|
+
}
|
|
29
|
+
async insertMany(jobs, rejectExisting = false) {
|
|
30
|
+
await this.initialize();
|
|
31
|
+
const insertSerially = () => runPostgresTransactionWithRetry(this.context, async (tx) => {
|
|
32
|
+
await lockPostgresAdmissionQueues(tx, this.context, jobs.map((job) => job.queue));
|
|
33
|
+
await lockPostgresDependencyCompletions(tx, this.context, admissionDependencyIds(jobs));
|
|
34
|
+
await lockPostgresFlowParents(tx, this.context, admissionParentIds(jobs));
|
|
35
|
+
await lockPostgresAdmissionKeys(tx, this.context, jobs);
|
|
36
|
+
const admissions = [];
|
|
37
|
+
const insertedJobIds = [];
|
|
38
|
+
const insertedDependencies = [];
|
|
39
|
+
for (const source of jobs) {
|
|
40
|
+
const job = replaySafeAdmissionJob(source);
|
|
41
|
+
const admitted = await admitPostgresJob(tx, this.context, job, {
|
|
42
|
+
rejectExisting,
|
|
43
|
+
dependencyLocksHeld: true,
|
|
44
|
+
queueLifecycleLocksHeld: true,
|
|
45
|
+
dependencyExistenceCheckDeferred: true,
|
|
46
|
+
completionConsumerExemptions: insertedJobIds,
|
|
47
|
+
});
|
|
48
|
+
admissions.push(admitted);
|
|
49
|
+
if (admitted.inserted) {
|
|
50
|
+
insertedJobIds.push(job.id);
|
|
51
|
+
insertedDependencies.push(...job.dependsOn);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
await assertPostgresDependenciesExist(tx, this.context, insertedDependencies);
|
|
55
|
+
return await reconcilePostgresSerialAdmissions(tx, this.context, admissions);
|
|
56
|
+
});
|
|
57
|
+
if (!canBatchAdmitPostgresJobs(jobs))
|
|
58
|
+
return await insertSerially();
|
|
59
|
+
try {
|
|
60
|
+
return await runPostgresTransactionWithRetry(this.context, (tx) => admitPostgresJobsBatch(tx, this.context, jobs));
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (!(error instanceof PostgresBatchAdmissionConflict))
|
|
64
|
+
throw error;
|
|
65
|
+
return await insertSerially();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async insertFlow(batch) {
|
|
69
|
+
validateAtomicFlowBatch(batch);
|
|
70
|
+
await this.initialize();
|
|
71
|
+
return await runPostgresTransactionWithRetry(this.context, async (tx) => {
|
|
72
|
+
const now = await databaseNow(tx);
|
|
73
|
+
const created = batch.jobs.map((planned) => createJob(planned.id, planned.queue, planned.input, now));
|
|
74
|
+
await lockPostgresAdmissionQueues(tx, this.context, created.map((job) => job.queue));
|
|
75
|
+
await lockPostgresDependencyCompletions(tx, this.context, admissionDependencyIds(created));
|
|
76
|
+
await retirePostgresCompletionGenerations(tx, this.context, created.map((job) => job.id));
|
|
77
|
+
await lockPostgresFlowParents(tx, this.context, admissionParentIds(created));
|
|
78
|
+
await lockPostgresAdmissionKeys(tx, this.context, created);
|
|
79
|
+
const admissionNow = await databaseNow(tx);
|
|
80
|
+
const jobs = [];
|
|
81
|
+
const admissions = [];
|
|
82
|
+
for (const job of created) {
|
|
83
|
+
const admitted = await admitPostgresJob(tx, this.context, job, {
|
|
84
|
+
rejectExisting: true,
|
|
85
|
+
linkParent: false,
|
|
86
|
+
dependencyLocksHeld: true,
|
|
87
|
+
queueLifecycleLocksHeld: true,
|
|
88
|
+
dependencyExistenceCheckDeferred: true,
|
|
89
|
+
preparedFlow: { now: admissionNow },
|
|
90
|
+
});
|
|
91
|
+
admissions.push(admitted);
|
|
92
|
+
jobs.push(admitted.job);
|
|
93
|
+
}
|
|
94
|
+
await assertPostgresDependenciesExist(tx, this.context, created.flatMap((job) => job.dependsOn));
|
|
95
|
+
const inserted = admissions.filter((admission) => admission.inserted);
|
|
96
|
+
await registerPostgresAdmissionQueues(tx, this.context, inserted.map(({ job }) => job.queue));
|
|
97
|
+
await recordPostgresJobEvents(tx, this.context, inserted.map(({ job, state }) => ({ job, state, type: 'pushed' })), admissionNow);
|
|
98
|
+
return jobs;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
function postgresCharacterLength(value) {
|
|
2
|
+
// oxlint-disable-next-line typescript/no-misused-spread -- PostgreSQL length(text) counts code points.
|
|
3
|
+
return [...value].length;
|
|
4
|
+
}
|
|
5
|
+
/** Build an unambiguous domain-separated advisory-lock identity. */
|
|
6
|
+
export function postgresAdvisoryLockName(domain, ...components) {
|
|
7
|
+
const base = `bunqueue:${domain}`;
|
|
8
|
+
if (components.length === 0)
|
|
9
|
+
return base;
|
|
10
|
+
return `${base}:${components
|
|
11
|
+
.map((component) => `${postgresCharacterLength(component)}:${component}`)
|
|
12
|
+
.join('')}`;
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TransactionSQL } from 'bun';
|
|
2
|
+
import { type Job } from '../../../domain/types/job';
|
|
3
|
+
import { type PostgresContext } from './context';
|
|
4
|
+
export declare class PostgresBatchAdmissionConflict extends Error {
|
|
5
|
+
constructor();
|
|
6
|
+
}
|
|
7
|
+
export declare function canBatchAdmitPostgresJobs(jobs: readonly Job[]): boolean;
|
|
8
|
+
/** Serialize every conflicting batch key in one canonically ordered round trip. */
|
|
9
|
+
export declare function lockPostgresAdmissionKeys(tx: TransactionSQL, ctx: PostgresContext, jobs: readonly Job[]): Promise<void>;
|
|
10
|
+
/** Admit independent jobs atomically with one insert and one event write. */
|
|
11
|
+
export declare function admitPostgresJobsBatch(tx: TransactionSQL, ctx: PostgresContext, jobs: readonly Job[]): Promise<Job[]>;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { MAX_TIMELINE_ENTRIES } from '../../../domain/types/job';
|
|
2
|
+
import { postgresAdvisoryLockName } from './advisoryLocks';
|
|
3
|
+
import { recordPostgresJobEvents } from './batchEvents';
|
|
4
|
+
import { encodePostgresValue, postgresStateForJob } from './codec';
|
|
5
|
+
import { databaseNow } from './context';
|
|
6
|
+
import { retirePostgresCompletionGenerations } from './completionLifecycle';
|
|
7
|
+
import { lockPostgresDependencyCompletions } from './dependencyPromotion';
|
|
8
|
+
import { lockPostgresAdmissionQueues, registerPostgresAdmissionQueues } from './queueLifecycle';
|
|
9
|
+
export class PostgresBatchAdmissionConflict extends Error {
|
|
10
|
+
constructor() {
|
|
11
|
+
super('PostgreSQL batch admission encountered an existing job ID');
|
|
12
|
+
this.name = 'PostgresBatchAdmissionConflict';
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export function canBatchAdmitPostgresJobs(jobs) {
|
|
16
|
+
if (jobs.length < 2)
|
|
17
|
+
return false;
|
|
18
|
+
if (new Set(jobs.map((job) => String(job.id))).size !== jobs.length)
|
|
19
|
+
return false;
|
|
20
|
+
return jobs.every((job) => job.dependsOn.length === 0 && job.parentId === null);
|
|
21
|
+
}
|
|
22
|
+
function admissionKeys(jobs) {
|
|
23
|
+
return [
|
|
24
|
+
...new Set(jobs.flatMap((job) => [
|
|
25
|
+
`id:${String(job.id)}`,
|
|
26
|
+
...(job.uniqueKey ? [`dedup:${job.queue}:${job.uniqueKey}`] : []),
|
|
27
|
+
])),
|
|
28
|
+
].sort();
|
|
29
|
+
}
|
|
30
|
+
/** Serialize every conflicting batch key in one canonically ordered round trip. */
|
|
31
|
+
export async function lockPostgresAdmissionKeys(tx, ctx, jobs) {
|
|
32
|
+
const lockNames = admissionKeys(jobs).map((key) => postgresAdvisoryLockName('admission', ctx.config.namespace, key));
|
|
33
|
+
if (lockNames.length === 0)
|
|
34
|
+
return;
|
|
35
|
+
await tx `
|
|
36
|
+
WITH ordered_keys AS MATERIALIZED (
|
|
37
|
+
SELECT DISTINCT hashtextextended(lock_name, 0) AS lock_key
|
|
38
|
+
FROM unnest(${tx.array(lockNames, 'TEXT')}) AS admission(lock_name)
|
|
39
|
+
ORDER BY lock_key
|
|
40
|
+
), locked_keys AS MATERIALIZED (
|
|
41
|
+
SELECT lock_key, pg_advisory_xact_lock(lock_key) AS acquired
|
|
42
|
+
FROM ordered_keys
|
|
43
|
+
ORDER BY lock_key
|
|
44
|
+
)
|
|
45
|
+
SELECT COUNT(*) FROM locked_keys
|
|
46
|
+
`;
|
|
47
|
+
}
|
|
48
|
+
function prepareAdmissions(jobs, now) {
|
|
49
|
+
return jobs.map((job) => {
|
|
50
|
+
const preparedJob = { ...job, timeline: [...job.timeline] };
|
|
51
|
+
if (preparedJob.runAt === preparedJob.createdAt)
|
|
52
|
+
preparedJob.runAt = now;
|
|
53
|
+
const state = postgresStateForJob(preparedJob, true, now);
|
|
54
|
+
if (preparedJob.timeline.length < MAX_TIMELINE_ENTRIES) {
|
|
55
|
+
preparedJob.timeline.push({ state, timestamp: now });
|
|
56
|
+
}
|
|
57
|
+
return { job: preparedJob, state };
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
function toRecords(prepared, namespace, now, groupOrders) {
|
|
61
|
+
return prepared.map(({ job, state }, position) => ({
|
|
62
|
+
namespace,
|
|
63
|
+
id: String(job.id),
|
|
64
|
+
queue: job.queue,
|
|
65
|
+
payload: encodePostgresValue(job),
|
|
66
|
+
state,
|
|
67
|
+
priority: job.priority,
|
|
68
|
+
lifo: job.lifo,
|
|
69
|
+
run_at: job.runAt,
|
|
70
|
+
created_at: job.createdAt,
|
|
71
|
+
started_at: job.startedAt,
|
|
72
|
+
completed_at: job.completedAt,
|
|
73
|
+
attempts: job.attempts,
|
|
74
|
+
max_attempts: job.maxAttempts,
|
|
75
|
+
ttl: job.ttl,
|
|
76
|
+
timeout: job.timeout,
|
|
77
|
+
unique_key: job.uniqueKey,
|
|
78
|
+
unique_expires_at: job.uniqueKey && job.deduplicationTtl !== null ? now + job.deduplicationTtl : null,
|
|
79
|
+
custom_id: job.customId,
|
|
80
|
+
group_id: job.groupId,
|
|
81
|
+
group_order: groupOrders.get(position) ?? null,
|
|
82
|
+
}));
|
|
83
|
+
}
|
|
84
|
+
async function allocateGroupOrders(tx, prepared) {
|
|
85
|
+
const positions = prepared.flatMap(({ job }, position) => job.groupId === null ? [] : [position]);
|
|
86
|
+
if (positions.length === 0)
|
|
87
|
+
return new Map();
|
|
88
|
+
const rows = await tx `
|
|
89
|
+
WITH ordered AS MATERIALIZED (
|
|
90
|
+
SELECT position
|
|
91
|
+
FROM unnest(${tx.array(positions, 'INTEGER')}) AS requested(position)
|
|
92
|
+
ORDER BY position
|
|
93
|
+
)
|
|
94
|
+
SELECT position, nextval('bunqueue_group_order_seq') AS group_order
|
|
95
|
+
FROM ordered
|
|
96
|
+
ORDER BY position
|
|
97
|
+
`;
|
|
98
|
+
return new Map(rows.map(({ position, group_order }) => [position, group_order]));
|
|
99
|
+
}
|
|
100
|
+
async function insertRows(tx, ctx, prepared, now) {
|
|
101
|
+
const groupOrders = await allocateGroupOrders(tx, prepared);
|
|
102
|
+
const records = toRecords(prepared, ctx.config.namespace, now, groupOrders);
|
|
103
|
+
let insertedCount = 0;
|
|
104
|
+
for (let offset = 0; offset < records.length; offset += 1000) {
|
|
105
|
+
const batch = records.slice(offset, offset + 1000);
|
|
106
|
+
const inserted = await tx `
|
|
107
|
+
INSERT INTO bunqueue_jobs ${tx(batch, 'namespace', 'id', 'queue', 'payload', 'state', 'priority', 'lifo', 'run_at', 'created_at', 'started_at', 'completed_at', 'attempts', 'max_attempts', 'ttl', 'timeout', 'unique_key', 'unique_expires_at', 'custom_id', 'group_id', 'group_order')}
|
|
108
|
+
ON CONFLICT DO NOTHING
|
|
109
|
+
RETURNING id
|
|
110
|
+
`;
|
|
111
|
+
insertedCount += inserted.length;
|
|
112
|
+
}
|
|
113
|
+
if (insertedCount !== prepared.length)
|
|
114
|
+
throw new PostgresBatchAdmissionConflict();
|
|
115
|
+
}
|
|
116
|
+
/** Admit independent jobs atomically with one insert and one event write. */
|
|
117
|
+
export async function admitPostgresJobsBatch(tx, ctx, jobs) {
|
|
118
|
+
await lockPostgresAdmissionQueues(tx, ctx, jobs.map((job) => job.queue));
|
|
119
|
+
await lockPostgresDependencyCompletions(tx, ctx, jobs.map((job) => job.id));
|
|
120
|
+
await lockPostgresAdmissionKeys(tx, ctx, jobs);
|
|
121
|
+
const now = await databaseNow(tx);
|
|
122
|
+
const prepared = prepareAdmissions(jobs, now);
|
|
123
|
+
await insertRows(tx, ctx, prepared, now);
|
|
124
|
+
await registerPostgresAdmissionQueues(tx, ctx, prepared.map(({ job }) => job.queue));
|
|
125
|
+
await retirePostgresCompletionGenerations(tx, ctx, jobs.map((job) => job.id));
|
|
126
|
+
await recordPostgresJobEvents(tx, ctx, prepared.map(({ job, state }) => ({ job, type: 'pushed', state })), now);
|
|
127
|
+
return prepared.map(({ job }) => job);
|
|
128
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type PostgresContext } from './context';
|
|
2
|
+
import type { PostgresBatchCompletionResult, PostgresCompletionInput } from './types';
|
|
3
|
+
/** Complete a unique ACK batch atomically with set-based persistence. */
|
|
4
|
+
export declare function completePostgresJobs(ctx: PostgresContext, inputs: readonly PostgresCompletionInput[]): Promise<PostgresBatchCompletionResult[]>;
|