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,45 @@
|
|
|
1
|
+
import type { PostgresContext } from './context';
|
|
2
|
+
import type { PostgresDeliveredStoreEvent } from './types';
|
|
3
|
+
type EventListener = (event: PostgresDeliveredStoreEvent) => void;
|
|
4
|
+
type InvalidationListener = (queue: string) => void;
|
|
5
|
+
type DrainStatusListener = (error: Error | null) => void;
|
|
6
|
+
export declare function postgresEventDrainBatchSize(maxQueueEvents: number): number;
|
|
7
|
+
/** Commit-ordered journal polling with LISTEN/NOTIFY used only as a wakeup hint. */
|
|
8
|
+
export declare class PostgresEventStream {
|
|
9
|
+
private readonly ctx;
|
|
10
|
+
private subscription;
|
|
11
|
+
private pollTimer;
|
|
12
|
+
private readonly listeners;
|
|
13
|
+
private readonly invalidationListeners;
|
|
14
|
+
private readonly drainStatusListeners;
|
|
15
|
+
private readonly waiters;
|
|
16
|
+
private readonly queueCursors;
|
|
17
|
+
private readonly retentionQueues;
|
|
18
|
+
private journalCursor;
|
|
19
|
+
private cursor;
|
|
20
|
+
private checkpointScanRequested;
|
|
21
|
+
private drainRequested;
|
|
22
|
+
private draining;
|
|
23
|
+
private retentionRetryTimer;
|
|
24
|
+
private closed;
|
|
25
|
+
constructor(ctx: PostgresContext);
|
|
26
|
+
start(): Promise<void>;
|
|
27
|
+
subscribe(listener: EventListener): () => void;
|
|
28
|
+
subscribeInvalidation(listener: InvalidationListener): () => void;
|
|
29
|
+
subscribeDrainStatus(listener: DrainStatusListener): () => void;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
wait(queue: string, timeoutMs: number, signal?: AbortSignal): Promise<void>;
|
|
32
|
+
private handleNotification;
|
|
33
|
+
private wake;
|
|
34
|
+
private wakeAll;
|
|
35
|
+
private removeWaiter;
|
|
36
|
+
private drain;
|
|
37
|
+
private drainLoop;
|
|
38
|
+
private convergeEventRetention;
|
|
39
|
+
private scheduleRetentionRetry;
|
|
40
|
+
private applyEvent;
|
|
41
|
+
private invalidateQueue;
|
|
42
|
+
private scanPruneWatermarks;
|
|
43
|
+
private reportDrainStatus;
|
|
44
|
+
}
|
|
45
|
+
export {};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import { latestPostgresEventJournalBaseline, loadPostgresJournalEventsAfter, } from './eventJournal';
|
|
2
|
+
import { PostgresEventCatchupCursors } from './eventCatchupCursors';
|
|
3
|
+
import { loadPostgresEventPruneWatermarks } from './eventPruneWatermarks';
|
|
4
|
+
import { POSTGRES_EVENT_CHANNEL } from './schema';
|
|
5
|
+
import { tryTrimPostgresQueueEvents } from './telemetry';
|
|
6
|
+
const MIN_EVENT_DRAIN_BATCH = 1_000;
|
|
7
|
+
const MAX_EVENT_DRAIN_BATCH = 4_096;
|
|
8
|
+
export function postgresEventDrainBatchSize(maxQueueEvents) {
|
|
9
|
+
return Math.max(MIN_EVENT_DRAIN_BATCH, Math.min(MAX_EVENT_DRAIN_BATCH, maxQueueEvents));
|
|
10
|
+
}
|
|
11
|
+
function requiresQueueInvalidation(event) {
|
|
12
|
+
return event.type.startsWith('queue-') || (!event.job && event.state === null);
|
|
13
|
+
}
|
|
14
|
+
/** Commit-ordered journal polling with LISTEN/NOTIFY used only as a wakeup hint. */
|
|
15
|
+
export class PostgresEventStream {
|
|
16
|
+
ctx;
|
|
17
|
+
subscription = null;
|
|
18
|
+
pollTimer = null;
|
|
19
|
+
listeners = new Set();
|
|
20
|
+
invalidationListeners = new Set();
|
|
21
|
+
drainStatusListeners = new Set();
|
|
22
|
+
waiters = new Map();
|
|
23
|
+
queueCursors = new PostgresEventCatchupCursors();
|
|
24
|
+
retentionQueues = new Set();
|
|
25
|
+
journalCursor = { commitSeq: 0, eventId: 0 };
|
|
26
|
+
cursor = 0;
|
|
27
|
+
checkpointScanRequested = false;
|
|
28
|
+
drainRequested = false;
|
|
29
|
+
draining = null;
|
|
30
|
+
retentionRetryTimer = null;
|
|
31
|
+
closed = false;
|
|
32
|
+
constructor(ctx) {
|
|
33
|
+
this.ctx = ctx;
|
|
34
|
+
}
|
|
35
|
+
async start() {
|
|
36
|
+
const [baseline, watermarks] = await Promise.all([
|
|
37
|
+
latestPostgresEventJournalBaseline(this.ctx),
|
|
38
|
+
loadPostgresEventPruneWatermarks(this.ctx),
|
|
39
|
+
]);
|
|
40
|
+
this.cursor = baseline.latestEventId;
|
|
41
|
+
this.journalCursor = { commitSeq: baseline.commitSeq, eventId: Number.MAX_SAFE_INTEGER };
|
|
42
|
+
this.queueCursors.reset(baseline.commitSeq);
|
|
43
|
+
for (const watermark of watermarks) {
|
|
44
|
+
if (watermark.commitSeq > baseline.commitSeq) {
|
|
45
|
+
this.queueCursors.applied(watermark.queue, watermark.commitSeq);
|
|
46
|
+
}
|
|
47
|
+
// `PostgresQueueManagerState` loads a full snapshot of every queue after
|
|
48
|
+
// this call, so recorded prunes are already covered and must not refresh
|
|
49
|
+
// the freshly loaded read model.
|
|
50
|
+
this.queueCursors.remember(watermark);
|
|
51
|
+
}
|
|
52
|
+
this.subscription = await this.ctx.sql.listen(POSTGRES_EVENT_CHANNEL, (payload) => this.handleNotification(payload), () => void this.drain());
|
|
53
|
+
this.pollTimer = setInterval(() => void this.drain(), this.ctx.config.pollIntervalMs);
|
|
54
|
+
}
|
|
55
|
+
subscribe(listener) {
|
|
56
|
+
this.listeners.add(listener);
|
|
57
|
+
return () => this.listeners.delete(listener);
|
|
58
|
+
}
|
|
59
|
+
subscribeInvalidation(listener) {
|
|
60
|
+
this.invalidationListeners.add(listener);
|
|
61
|
+
return () => this.invalidationListeners.delete(listener);
|
|
62
|
+
}
|
|
63
|
+
subscribeDrainStatus(listener) {
|
|
64
|
+
this.drainStatusListeners.add(listener);
|
|
65
|
+
return () => this.drainStatusListeners.delete(listener);
|
|
66
|
+
}
|
|
67
|
+
async close() {
|
|
68
|
+
this.closed = true;
|
|
69
|
+
if (this.pollTimer)
|
|
70
|
+
clearInterval(this.pollTimer);
|
|
71
|
+
this.pollTimer = null;
|
|
72
|
+
if (this.retentionRetryTimer)
|
|
73
|
+
clearTimeout(this.retentionRetryTimer);
|
|
74
|
+
this.retentionRetryTimer = null;
|
|
75
|
+
await this.subscription?.unlisten();
|
|
76
|
+
this.subscription = null;
|
|
77
|
+
for (const registrations of this.waiters.values()) {
|
|
78
|
+
for (const registration of [...registrations])
|
|
79
|
+
registration.resolve();
|
|
80
|
+
}
|
|
81
|
+
this.waiters.clear();
|
|
82
|
+
await this.draining;
|
|
83
|
+
}
|
|
84
|
+
wait(queue, timeoutMs, signal) {
|
|
85
|
+
if (this.closed || timeoutMs <= 0 || signal?.aborted)
|
|
86
|
+
return Promise.resolve();
|
|
87
|
+
return new Promise((resolve) => {
|
|
88
|
+
const finish = () => {
|
|
89
|
+
this.removeWaiter(queue, registration);
|
|
90
|
+
resolve();
|
|
91
|
+
};
|
|
92
|
+
const onAbort = () => finish();
|
|
93
|
+
const registration = {
|
|
94
|
+
resolve: finish,
|
|
95
|
+
timer: setTimeout(finish, timeoutMs),
|
|
96
|
+
...(signal && { signal, onAbort }),
|
|
97
|
+
};
|
|
98
|
+
let registrations = this.waiters.get(queue);
|
|
99
|
+
if (!registrations) {
|
|
100
|
+
registrations = new Set();
|
|
101
|
+
this.waiters.set(queue, registrations);
|
|
102
|
+
}
|
|
103
|
+
registrations.add(registration);
|
|
104
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
handleNotification(payload) {
|
|
108
|
+
try {
|
|
109
|
+
const parsed = JSON.parse(payload);
|
|
110
|
+
if (parsed.namespace !== this.ctx.config.namespace)
|
|
111
|
+
return;
|
|
112
|
+
if (parsed.queue)
|
|
113
|
+
this.wake(parsed.queue);
|
|
114
|
+
if (parsed.scanPruneWatermarks === true ||
|
|
115
|
+
(Number.isSafeInteger(parsed.prunedThrough) && parsed.prunedThrough > 0)) {
|
|
116
|
+
this.checkpointScanRequested = true;
|
|
117
|
+
}
|
|
118
|
+
if (parsed.queue && parsed.retentionRequested === true) {
|
|
119
|
+
this.retentionQueues.add(parsed.queue);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
this.checkpointScanRequested = true;
|
|
124
|
+
this.wakeAll();
|
|
125
|
+
}
|
|
126
|
+
void this.drain(false);
|
|
127
|
+
}
|
|
128
|
+
wake(queue) {
|
|
129
|
+
const registrations = this.waiters.get(queue);
|
|
130
|
+
if (!registrations)
|
|
131
|
+
return;
|
|
132
|
+
for (const registration of [...registrations])
|
|
133
|
+
registration.resolve();
|
|
134
|
+
}
|
|
135
|
+
wakeAll() {
|
|
136
|
+
for (const queue of this.waiters.keys())
|
|
137
|
+
this.wake(queue);
|
|
138
|
+
}
|
|
139
|
+
removeWaiter(queue, registration) {
|
|
140
|
+
const registrations = this.waiters.get(queue);
|
|
141
|
+
registrations?.delete(registration);
|
|
142
|
+
if (registrations?.size === 0)
|
|
143
|
+
this.waiters.delete(queue);
|
|
144
|
+
clearTimeout(registration.timer);
|
|
145
|
+
if (registration.signal && registration.onAbort) {
|
|
146
|
+
registration.signal.removeEventListener('abort', registration.onAbort);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async drain(scanPruneWatermarks = true) {
|
|
150
|
+
if (scanPruneWatermarks)
|
|
151
|
+
this.checkpointScanRequested = true;
|
|
152
|
+
this.drainRequested = true;
|
|
153
|
+
if (this.closed)
|
|
154
|
+
return;
|
|
155
|
+
if (this.draining)
|
|
156
|
+
return this.draining;
|
|
157
|
+
this.draining = this.drainLoop()
|
|
158
|
+
.then(() => {
|
|
159
|
+
if (!this.closed && !this.retentionRetryTimer)
|
|
160
|
+
this.reportDrainStatus(null);
|
|
161
|
+
})
|
|
162
|
+
.catch((error) => {
|
|
163
|
+
this.reportDrainStatus(error instanceof Error ? error : new Error(String(error)));
|
|
164
|
+
this.scheduleRetentionRetry();
|
|
165
|
+
})
|
|
166
|
+
.finally(() => {
|
|
167
|
+
this.draining = null;
|
|
168
|
+
if (this.drainRequested && !this.closed)
|
|
169
|
+
void this.drain(false);
|
|
170
|
+
});
|
|
171
|
+
return this.draining;
|
|
172
|
+
}
|
|
173
|
+
async drainLoop() {
|
|
174
|
+
const batchSize = postgresEventDrainBatchSize(this.ctx.config.maxQueueEvents);
|
|
175
|
+
while (!this.closed) {
|
|
176
|
+
this.drainRequested = false;
|
|
177
|
+
await this.convergeEventRetention();
|
|
178
|
+
await this.scanPruneWatermarks();
|
|
179
|
+
const entries = await loadPostgresJournalEventsAfter(this.ctx, this.journalCursor, batchSize);
|
|
180
|
+
// Always re-check retention against the pre-batch position: a prune that
|
|
181
|
+
// committed after the previous scan can have removed queue history this
|
|
182
|
+
// batch does not contain, and applying the batch would hide the gap.
|
|
183
|
+
if (entries.length > 0)
|
|
184
|
+
this.checkpointScanRequested = true;
|
|
185
|
+
await this.scanPruneWatermarks();
|
|
186
|
+
for (const entry of entries)
|
|
187
|
+
this.applyEvent(entry);
|
|
188
|
+
if (entries.length >= batchSize || this.drainRequested)
|
|
189
|
+
continue;
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
async convergeEventRetention() {
|
|
194
|
+
if (this.retentionRetryTimer)
|
|
195
|
+
return;
|
|
196
|
+
const maxLength = this.ctx.config.maxQueueEvents;
|
|
197
|
+
const queues = [...this.retentionQueues].sort();
|
|
198
|
+
for (const queue of queues) {
|
|
199
|
+
this.retentionQueues.delete(queue);
|
|
200
|
+
try {
|
|
201
|
+
const removed = await tryTrimPostgresQueueEvents(this.ctx, queue, maxLength);
|
|
202
|
+
if (removed === null) {
|
|
203
|
+
this.retentionQueues.add(queue);
|
|
204
|
+
this.scheduleRetentionRetry();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch (error) {
|
|
208
|
+
this.retentionQueues.add(queue);
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
scheduleRetentionRetry() {
|
|
214
|
+
if (this.closed || this.retentionRetryTimer || this.retentionQueues.size === 0)
|
|
215
|
+
return;
|
|
216
|
+
const delay = Math.min(this.ctx.config.pollIntervalMs, 250);
|
|
217
|
+
this.retentionRetryTimer = setTimeout(() => {
|
|
218
|
+
this.retentionRetryTimer = null;
|
|
219
|
+
if (!this.closed && this.retentionQueues.size > 0)
|
|
220
|
+
void this.drain(false);
|
|
221
|
+
}, delay);
|
|
222
|
+
}
|
|
223
|
+
applyEvent(entry) {
|
|
224
|
+
const { event, commitSeq } = entry;
|
|
225
|
+
this.journalCursor = { commitSeq, eventId: event.id };
|
|
226
|
+
this.cursor = Math.max(this.cursor, event.id);
|
|
227
|
+
this.queueCursors.applied(event.queue, commitSeq);
|
|
228
|
+
if (requiresQueueInvalidation(event))
|
|
229
|
+
this.invalidateQueue(event.queue);
|
|
230
|
+
const delivered = { ...event, commitSeq };
|
|
231
|
+
for (const listener of this.listeners) {
|
|
232
|
+
try {
|
|
233
|
+
listener(delivered);
|
|
234
|
+
}
|
|
235
|
+
catch {
|
|
236
|
+
// Listener isolation: one observer cannot stop durable cursor progress.
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
invalidateQueue(queue) {
|
|
241
|
+
for (const listener of this.invalidationListeners) {
|
|
242
|
+
try {
|
|
243
|
+
listener(queue);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Invalidation observers cannot interrupt durable cursor progress.
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
async scanPruneWatermarks() {
|
|
251
|
+
if (!this.checkpointScanRequested)
|
|
252
|
+
return;
|
|
253
|
+
this.checkpointScanRequested = false;
|
|
254
|
+
try {
|
|
255
|
+
const watermarks = await loadPostgresEventPruneWatermarks(this.ctx);
|
|
256
|
+
for (const watermark of watermarks) {
|
|
257
|
+
if (this.queueCursors.requiresRefresh(watermark))
|
|
258
|
+
this.invalidateQueue(watermark.queue);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (error) {
|
|
262
|
+
this.checkpointScanRequested = true;
|
|
263
|
+
throw error;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
reportDrainStatus(error) {
|
|
267
|
+
for (const listener of this.drainStatusListeners) {
|
|
268
|
+
try {
|
|
269
|
+
listener(error);
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Diagnostics must not stop the next polling retry.
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jobId } from '../../../domain/types/job';
|
|
2
|
+
import { decodePostgresJob } from './codec';
|
|
3
|
+
import { databaseNow, recordPostgresEvent } from './context';
|
|
4
|
+
import { lockPostgresDestructionCandidates, partitionPostgresDestructionCandidates, } from './dependencyDestruction';
|
|
5
|
+
/** Delete pending jobs whose TTL elapsed, matching the existing SQLite pull semantics. */
|
|
6
|
+
export async function expirePendingPostgresJobs(ctx, queue, requestedNow) {
|
|
7
|
+
return await ctx.sql.begin(async (tx) => {
|
|
8
|
+
const now = requestedNow ?? (await databaseNow(tx));
|
|
9
|
+
const candidates = await tx `
|
|
10
|
+
SELECT id FROM bunqueue_jobs
|
|
11
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
12
|
+
AND queue = ${queue}
|
|
13
|
+
AND state IN ('waiting', 'prioritized', 'delayed')
|
|
14
|
+
AND ttl IS NOT NULL
|
|
15
|
+
AND created_at + ttl < ${now}
|
|
16
|
+
ORDER BY created_at, id
|
|
17
|
+
LIMIT 1000
|
|
18
|
+
`;
|
|
19
|
+
const candidateIds = candidates.map((row) => jobId(row.id));
|
|
20
|
+
if (candidateIds.length === 0)
|
|
21
|
+
return 0;
|
|
22
|
+
await lockPostgresDestructionCandidates(tx, ctx, candidateIds);
|
|
23
|
+
const rows = await tx `
|
|
24
|
+
SELECT * FROM bunqueue_jobs
|
|
25
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
26
|
+
AND queue = ${queue}
|
|
27
|
+
AND state IN ('waiting', 'prioritized', 'delayed')
|
|
28
|
+
AND ttl IS NOT NULL
|
|
29
|
+
AND created_at + ttl < ${now}
|
|
30
|
+
AND id = ANY(${tx.array(candidateIds.map(String), 'TEXT')})
|
|
31
|
+
ORDER BY created_at, id
|
|
32
|
+
`;
|
|
33
|
+
const plannedIds = rows.map((row) => jobId(row.id));
|
|
34
|
+
const { deletableIds } = await partitionPostgresDestructionCandidates(tx, ctx, plannedIds, plannedIds);
|
|
35
|
+
const deletable = new Set(deletableIds.map(String));
|
|
36
|
+
const removedRows = rows.filter((row) => deletable.has(row.id));
|
|
37
|
+
if (removedRows.length === 0)
|
|
38
|
+
return 0;
|
|
39
|
+
const ids = removedRows.map((row) => row.id);
|
|
40
|
+
await tx `
|
|
41
|
+
DELETE FROM bunqueue_job_logs
|
|
42
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ANY(${tx.array(ids, 'TEXT')})
|
|
43
|
+
`;
|
|
44
|
+
await tx `
|
|
45
|
+
DELETE FROM bunqueue_flow_failures
|
|
46
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
47
|
+
AND parent_id = ANY(${tx.array(ids, 'TEXT')})
|
|
48
|
+
`;
|
|
49
|
+
await tx `
|
|
50
|
+
DELETE FROM bunqueue_dependencies
|
|
51
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
52
|
+
AND job_id = ANY(${tx.array(ids, 'TEXT')})
|
|
53
|
+
`;
|
|
54
|
+
await tx `
|
|
55
|
+
DELETE FROM bunqueue_jobs
|
|
56
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
57
|
+
AND id = ANY(${tx.array(ids, 'TEXT')})
|
|
58
|
+
`;
|
|
59
|
+
for (const row of removedRows) {
|
|
60
|
+
const job = decodePostgresJob(row).job;
|
|
61
|
+
await recordPostgresEvent(tx, ctx, {
|
|
62
|
+
queue,
|
|
63
|
+
type: 'removed',
|
|
64
|
+
jobId: job.id,
|
|
65
|
+
occurredAt: now,
|
|
66
|
+
job,
|
|
67
|
+
state: row.state,
|
|
68
|
+
error: 'Job TTL expired',
|
|
69
|
+
removed: true,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return removedRows.length;
|
|
73
|
+
});
|
|
74
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TransactionSQL } from 'bun';
|
|
2
|
+
import { type Job, type JobId } from '../../../domain/types/job';
|
|
3
|
+
import { type PostgresContext } from './context';
|
|
4
|
+
export interface PostgresDlqLimitRequest {
|
|
5
|
+
readonly queue: string;
|
|
6
|
+
readonly maxEntries: number;
|
|
7
|
+
}
|
|
8
|
+
/** Serialize mutations involving one flow parent across brokers. */
|
|
9
|
+
export declare function lockPostgresFlowParent(tx: TransactionSQL, ctx: PostgresContext, parentId: JobId): Promise<void>;
|
|
10
|
+
/** Acquire a flow-parent batch in canonical order with one database round trip. */
|
|
11
|
+
export declare function lockPostgresFlowParents(tx: TransactionSQL, ctx: PostgresContext, parentIds: readonly JobId[]): Promise<void>;
|
|
12
|
+
/** Lock child attachment, then its current parent, before a terminal row mutation. */
|
|
13
|
+
export declare function lockPostgresJobFlowParent(tx: TransactionSQL, ctx: PostgresContext, childId: JobId): Promise<void>;
|
|
14
|
+
/** Apply a terminal child's configured parent policy in the same transaction. */
|
|
15
|
+
export declare function applyPostgresFlowFailure(tx: TransactionSQL, ctx: PostgresContext, child: Job, errorValue: string | undefined, now: number): Promise<PostgresDlqLimitRequest | null>;
|
|
16
|
+
export declare function clearPostgresParentFlowFailures(tx: TransactionSQL, ctx: PostgresContext, parentId: JobId): Promise<void>;
|
|
17
|
+
export declare function getPostgresFlowFailureValues(ctx: PostgresContext, parentId: JobId, mode: 'ignore' | 'continue'): Promise<Record<string, string>>;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { createDlqEntry } from '../../../domain/types/dlq';
|
|
2
|
+
import { MAX_TIMELINE_ENTRIES } from '../../../domain/types/job';
|
|
3
|
+
import { postgresAdvisoryLockName } from './advisoryLocks';
|
|
4
|
+
import { decodePostgresJob, encodePostgresValue } from './codec';
|
|
5
|
+
import { recordPostgresEvent } from './context';
|
|
6
|
+
import { getPostgresQueuePolicies } from './policies';
|
|
7
|
+
import { lockPostgresDependencyCompletions } from './dependencyPromotion';
|
|
8
|
+
const LINKABLE_STATES = [
|
|
9
|
+
'waiting',
|
|
10
|
+
'prioritized',
|
|
11
|
+
'delayed',
|
|
12
|
+
'waiting-children',
|
|
13
|
+
];
|
|
14
|
+
function failureMode(job) {
|
|
15
|
+
if (!job.parentId)
|
|
16
|
+
return null;
|
|
17
|
+
if (job.failParentOnFailure)
|
|
18
|
+
return 'fail';
|
|
19
|
+
if (job.continueParentOnFailure)
|
|
20
|
+
return 'continue';
|
|
21
|
+
if (job.ignoreDependencyOnFailure)
|
|
22
|
+
return 'ignore';
|
|
23
|
+
if (job.removeDependencyOnFailure)
|
|
24
|
+
return 'remove';
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function readyState(job, now) {
|
|
28
|
+
if (job.runAt > now)
|
|
29
|
+
return 'delayed';
|
|
30
|
+
return job.priority > 0 ? 'prioritized' : 'waiting';
|
|
31
|
+
}
|
|
32
|
+
async function storeFailureValue(input, mode) {
|
|
33
|
+
const { tx, ctx, child, error, now } = input;
|
|
34
|
+
await tx `
|
|
35
|
+
INSERT INTO bunqueue_flow_failures
|
|
36
|
+
(namespace, parent_id, child_id, child_queue, mode, error, created_at)
|
|
37
|
+
VALUES
|
|
38
|
+
(${ctx.config.namespace}, ${String(child.parentId)}, ${String(child.id)}, ${child.queue},
|
|
39
|
+
${mode}, ${error}, ${now})
|
|
40
|
+
ON CONFLICT (namespace, parent_id, child_id) DO UPDATE SET
|
|
41
|
+
child_queue = excluded.child_queue,
|
|
42
|
+
mode = excluded.mode,
|
|
43
|
+
error = excluded.error,
|
|
44
|
+
created_at = excluded.created_at
|
|
45
|
+
`;
|
|
46
|
+
}
|
|
47
|
+
async function unresolvedCount(tx, ctx, parentId) {
|
|
48
|
+
const [row] = await tx `
|
|
49
|
+
SELECT COUNT(*)::bigint AS count
|
|
50
|
+
FROM bunqueue_dependencies AS dependency
|
|
51
|
+
WHERE dependency.namespace = ${ctx.config.namespace}
|
|
52
|
+
AND dependency.job_id = ${String(parentId)}
|
|
53
|
+
AND NOT EXISTS (
|
|
54
|
+
SELECT 1 FROM bunqueue_completions AS completion
|
|
55
|
+
WHERE completion.namespace = dependency.namespace
|
|
56
|
+
AND completion.job_id = dependency.dependency_id
|
|
57
|
+
)
|
|
58
|
+
`;
|
|
59
|
+
return Number(row.count);
|
|
60
|
+
}
|
|
61
|
+
async function failParent(input) {
|
|
62
|
+
const { tx, ctx, parent, child, error, now } = input;
|
|
63
|
+
const message = `Child job ${String(child.id)} failed: ${error}`;
|
|
64
|
+
parent.completedAt = now;
|
|
65
|
+
if (parent.timeline.length < MAX_TIMELINE_ENTRIES) {
|
|
66
|
+
parent.timeline.push({ state: 'failed', timestamp: now, error: message });
|
|
67
|
+
}
|
|
68
|
+
const { dlq } = await getPostgresQueuePolicies(tx, ctx, parent.queue);
|
|
69
|
+
const entry = createDlqEntry(parent, "unknown" /* FailureReason.Unknown */, message, dlq, now);
|
|
70
|
+
await tx `
|
|
71
|
+
DELETE FROM bunqueue_dependencies
|
|
72
|
+
WHERE namespace = ${ctx.config.namespace} AND job_id = ${String(parent.id)}
|
|
73
|
+
`;
|
|
74
|
+
await tx `
|
|
75
|
+
DELETE FROM bunqueue_flow_failures
|
|
76
|
+
WHERE namespace = ${ctx.config.namespace} AND parent_id = ${String(parent.id)}
|
|
77
|
+
`;
|
|
78
|
+
await tx `
|
|
79
|
+
UPDATE bunqueue_jobs
|
|
80
|
+
SET payload = ${encodePostgresValue(parent)}, state = 'failed', completed_at = ${now},
|
|
81
|
+
error = ${message}, failure_reason = ${"unknown" /* FailureReason.Unknown */},
|
|
82
|
+
dlq_entry = ${encodePostgresValue(entry)}, dlq_retry_state = NULL,
|
|
83
|
+
version = version + 1
|
|
84
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${String(parent.id)}
|
|
85
|
+
`;
|
|
86
|
+
await recordPostgresEvent(tx, ctx, {
|
|
87
|
+
queue: parent.queue,
|
|
88
|
+
type: 'failed',
|
|
89
|
+
jobId: parent.id,
|
|
90
|
+
occurredAt: now,
|
|
91
|
+
job: parent,
|
|
92
|
+
state: 'failed',
|
|
93
|
+
error: message,
|
|
94
|
+
dlqEntry: entry,
|
|
95
|
+
dlqRetryState: null,
|
|
96
|
+
});
|
|
97
|
+
return { queue: parent.queue, maxEntries: dlq.maxEntries };
|
|
98
|
+
}
|
|
99
|
+
async function releaseDependencies(input, mode) {
|
|
100
|
+
const { tx, ctx, parent, child, now } = input;
|
|
101
|
+
if (mode === 'ignore' || mode === 'continue') {
|
|
102
|
+
await storeFailureValue(input, mode);
|
|
103
|
+
}
|
|
104
|
+
const released = mode === 'continue' ? [...parent.dependsOn] : [child.id];
|
|
105
|
+
const remaining = parent.dependsOn.filter((id) => !released.includes(id));
|
|
106
|
+
await tx `
|
|
107
|
+
DELETE FROM bunqueue_dependencies
|
|
108
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
109
|
+
AND job_id = ${String(parent.id)}
|
|
110
|
+
AND dependency_id = ANY(${tx.array(released.map(String), 'TEXT')})
|
|
111
|
+
`;
|
|
112
|
+
const resolved = (await unresolvedCount(tx, ctx, parent.id)) === 0;
|
|
113
|
+
const updated = { ...parent, dependsOn: remaining };
|
|
114
|
+
const state = resolved ? readyState(updated, now) : 'waiting-children';
|
|
115
|
+
await tx `
|
|
116
|
+
UPDATE bunqueue_jobs
|
|
117
|
+
SET payload = ${encodePostgresValue(updated)}, state = ${state}, version = version + 1
|
|
118
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${String(parent.id)}
|
|
119
|
+
`;
|
|
120
|
+
if (resolved) {
|
|
121
|
+
await recordPostgresEvent(tx, ctx, {
|
|
122
|
+
queue: parent.queue,
|
|
123
|
+
type: 'retried',
|
|
124
|
+
jobId: parent.id,
|
|
125
|
+
occurredAt: now,
|
|
126
|
+
job: updated,
|
|
127
|
+
state,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** Serialize mutations involving one flow parent across brokers. */
|
|
132
|
+
export async function lockPostgresFlowParent(tx, ctx, parentId) {
|
|
133
|
+
await lockPostgresFlowParents(tx, ctx, [parentId]);
|
|
134
|
+
}
|
|
135
|
+
/** Acquire a flow-parent batch in canonical order with one database round trip. */
|
|
136
|
+
export async function lockPostgresFlowParents(tx, ctx, parentIds) {
|
|
137
|
+
const lockNames = [...new Set(parentIds.map(String))].map((id) => postgresAdvisoryLockName('flow', ctx.config.namespace, id));
|
|
138
|
+
if (lockNames.length === 0)
|
|
139
|
+
return;
|
|
140
|
+
await tx `
|
|
141
|
+
WITH ordered_ids AS MATERIALIZED (
|
|
142
|
+
SELECT DISTINCT hashtextextended(lock_name, 0) AS lock_key
|
|
143
|
+
FROM unnest(${tx.array(lockNames, 'TEXT')}) AS parent(lock_name)
|
|
144
|
+
ORDER BY lock_key
|
|
145
|
+
), locked_ids AS MATERIALIZED (
|
|
146
|
+
SELECT lock_key, pg_advisory_xact_lock(lock_key) AS acquired
|
|
147
|
+
FROM ordered_ids
|
|
148
|
+
ORDER BY lock_key
|
|
149
|
+
)
|
|
150
|
+
SELECT COUNT(*) FROM locked_ids
|
|
151
|
+
`;
|
|
152
|
+
}
|
|
153
|
+
/** Lock child attachment, then its current parent, before a terminal row mutation. */
|
|
154
|
+
export async function lockPostgresJobFlowParent(tx, ctx, childId) {
|
|
155
|
+
await lockPostgresDependencyCompletions(tx, ctx, [childId]);
|
|
156
|
+
const [row] = await tx `
|
|
157
|
+
SELECT parent_id FROM bunqueue_jobs
|
|
158
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${String(childId)}
|
|
159
|
+
`;
|
|
160
|
+
if (row?.parent_id)
|
|
161
|
+
await lockPostgresFlowParent(tx, ctx, row.parent_id);
|
|
162
|
+
}
|
|
163
|
+
/** Apply a terminal child's configured parent policy in the same transaction. */
|
|
164
|
+
export async function applyPostgresFlowFailure(tx, ctx, child, errorValue, now) {
|
|
165
|
+
const mode = failureMode(child);
|
|
166
|
+
if (!mode || !child.parentId)
|
|
167
|
+
return null;
|
|
168
|
+
const rows = await tx `
|
|
169
|
+
SELECT * FROM bunqueue_jobs
|
|
170
|
+
WHERE namespace = ${ctx.config.namespace} AND id = ${String(child.parentId)}
|
|
171
|
+
FOR UPDATE
|
|
172
|
+
`;
|
|
173
|
+
const row = rows[0];
|
|
174
|
+
if (!row || !LINKABLE_STATES.includes(row.state))
|
|
175
|
+
return null;
|
|
176
|
+
const parent = decodePostgresJob(row).job;
|
|
177
|
+
const error = errorValue ?? 'unknown error';
|
|
178
|
+
const input = { tx, ctx, parent, child, error, now };
|
|
179
|
+
if (mode === 'fail')
|
|
180
|
+
return await failParent(input);
|
|
181
|
+
await releaseDependencies(input, mode);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
export async function clearPostgresParentFlowFailures(tx, ctx, parentId) {
|
|
185
|
+
await tx `
|
|
186
|
+
DELETE FROM bunqueue_flow_failures
|
|
187
|
+
WHERE namespace = ${ctx.config.namespace} AND parent_id = ${String(parentId)}
|
|
188
|
+
`;
|
|
189
|
+
}
|
|
190
|
+
export async function getPostgresFlowFailureValues(ctx, parentId, mode) {
|
|
191
|
+
const rows = await ctx.sql `
|
|
192
|
+
SELECT child_id, child_queue, error
|
|
193
|
+
FROM bunqueue_flow_failures
|
|
194
|
+
WHERE namespace = ${ctx.config.namespace}
|
|
195
|
+
AND parent_id = ${String(parentId)} AND mode = ${mode}
|
|
196
|
+
ORDER BY created_at, child_id
|
|
197
|
+
`;
|
|
198
|
+
return Object.fromEntries(rows.map((row) => [`${row.child_queue}:${row.child_id}`, row.error]));
|
|
199
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { TransactionSQL } from 'bun';
|
|
2
|
+
import type { GroupPullOptions } from '../../../domain/types/group';
|
|
3
|
+
import type { PostgresContext } from './context';
|
|
4
|
+
import type { PostgresJobRow } from './types';
|
|
5
|
+
/** Assign durable rotation positions to every pending group lacking one. */
|
|
6
|
+
export declare function ensurePostgresGroupStates(tx: TransactionSQL, ctx: PostgresContext, queue: string, sequence: number): Promise<number>;
|
|
7
|
+
/** Reset fixed windows when they expire or a worker changes the effective defaults. */
|
|
8
|
+
export declare function refreshPostgresGroupRateWindows(tx: TransactionSQL, ctx: PostgresContext, queue: string, options: GroupPullOptions | undefined, now: number): Promise<void>;
|
|
9
|
+
/** Consume group budgets and move the durable round-robin cursor after row locks are secured. */
|
|
10
|
+
export declare function commitPostgresGroupClaims(tx: TransactionSQL, ctx: PostgresContext, input: {
|
|
11
|
+
queue: string;
|
|
12
|
+
rows: readonly PostgresJobRow[];
|
|
13
|
+
options?: GroupPullOptions;
|
|
14
|
+
sequence: number;
|
|
15
|
+
}): Promise<void>;
|