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
package/README.md
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
</p>
|
|
14
14
|
|
|
15
15
|
<p align="center">
|
|
16
|
-
High-performance job queue for Bun.
|
|
17
|
-
|
|
16
|
+
High-performance job queue for Bun. Memory or one-file SQLite; PostgreSQL 15–18 multi-broker when you scale.<br/>
|
|
17
|
+
DLQ, cron, SQLite S3 backups, and native MCP. Built for AI agents and automation. No Redis.
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
@@ -48,14 +48,13 @@ await app.add('send', { to: 'alice@example.com' });
|
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
That's it. Queue + Worker in one object, persisted to a single SQLite file.
|
|
51
|
-
No Redis, no config, no setup.
|
|
52
|
-
|
|
53
|
-
built-ins.
|
|
51
|
+
No Redis, no config, no setup. `msgpackr` is the only runtime dependency;
|
|
52
|
+
cron, SQLite, S3, HTTP and WebSocket use Bun's built-ins.
|
|
54
53
|
|
|
55
54
|
### Not on Bun? Run the server, connect from anywhere
|
|
56
55
|
|
|
57
|
-
The queue also runs as a standalone server
|
|
58
|
-
|
|
56
|
+
The queue also runs as a standalone server. Memory is the zero-configuration
|
|
57
|
+
default; SQLite is the zero-infrastructure persistent option:
|
|
59
58
|
|
|
60
59
|
```bash
|
|
61
60
|
# in-memory without --data-path; pass it to persist jobs to SQLite
|
|
@@ -67,9 +66,28 @@ docker run -d -p 6789:6789 -p 6790:6790 \
|
|
|
67
66
|
ghcr.io/egeominotti/bunqueue:latest
|
|
68
67
|
```
|
|
69
68
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
For multiple active brokers, the repository includes a topology pinned to
|
|
70
|
+
PostgreSQL 18.6:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
POSTGRES_PASSWORD='replace-me' \
|
|
74
|
+
BUNQUEUE_POSTGRES_URL='postgres://bunqueue:replace-me@postgres:5432/bunqueue' \
|
|
75
|
+
docker compose -f docker-compose.postgres.yml up --build -d
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
It starts two brokers against one database/namespace. PostgreSQL is server-only;
|
|
79
|
+
embedded mode keeps using memory/SQLite. Supply both Compose values when the
|
|
80
|
+
password changes, percent-encoding reserved characters in the URL only. MySQL
|
|
81
|
+
is not supported. CI validates PostgreSQL 15, 16, 17, and the pinned/recommended
|
|
82
|
+
18.6 release. See the
|
|
83
|
+
[storage guide](https://bunqueue.dev/guide/databases/).
|
|
84
|
+
|
|
85
|
+
Every completed release publishes `ghcr.io/egeominotti/bunqueue` with the exact
|
|
86
|
+
version tag alongside `latest`, the commit SHA and a build timestamp, so pin the
|
|
87
|
+
version tag for reproducible deployments. Confirm the tag exists before pinning
|
|
88
|
+
it, because a release whose pipeline does not complete pushes no image;
|
|
89
|
+
`docker buildx imagetools inspect ghcr.io/egeominotti/bunqueue:<tag>` resolves
|
|
90
|
+
the digest.
|
|
73
91
|
|
|
74
92
|
Then produce and process from the language you already use:
|
|
75
93
|
|
|
@@ -80,7 +98,7 @@ npm install bunqueue-client # Node.js ≥ 20, Deno ≥ 2, Bun, Cloudflare Wor
|
|
|
80
98
|
```typescript
|
|
81
99
|
import { Queue, Worker } from 'bunqueue-client';
|
|
82
100
|
|
|
83
|
-
const queue = new Queue('emails');
|
|
101
|
+
const queue = new Queue('emails'); // localhost:6789 by default
|
|
84
102
|
await queue.add('welcome', { to: 'user@example.com' });
|
|
85
103
|
|
|
86
104
|
new Worker('emails', async (job) => ({ sent: true }), { concurrency: 10 });
|
|
@@ -96,14 +114,19 @@ Python, PHP, Go, Rust and Elixir clients speak the same protocol — see
|
|
|
96
114
|
|
|
97
115
|
## Why bunqueue?
|
|
98
116
|
|
|
99
|
-
| Library | Requires
|
|
100
|
-
| ------------ |
|
|
101
|
-
| BullMQ | Redis
|
|
102
|
-
| Agenda | MongoDB
|
|
103
|
-
| pg-boss | PostgreSQL
|
|
104
|
-
| **bunqueue** | **Nothing** | **Yes** |
|
|
105
|
-
|
|
106
|
-
- **Zero external infrastructure** —
|
|
117
|
+
| Library | Requires | AI-native |
|
|
118
|
+
| ------------ | ------------------------------------------ | --------- |
|
|
119
|
+
| BullMQ | Redis | No |
|
|
120
|
+
| Agenda | MongoDB | No |
|
|
121
|
+
| pg-boss | PostgreSQL | No |
|
|
122
|
+
| **bunqueue** | **Nothing (memory/SQLite) · PostgreSQL optional** | **Yes** |
|
|
123
|
+
|
|
124
|
+
- **Zero external infrastructure by default** — memory by default; one SQLite
|
|
125
|
+
file when local persistence is configured
|
|
126
|
+
- **PostgreSQL 15–18 multi-broker mode** — PostgreSQL 18.6 is recommended;
|
|
127
|
+
database-authoritative claims, fenced
|
|
128
|
+
leases, shared limits, cron, workers, job-state/lifecycle metrics, and failover state
|
|
129
|
+
([tested three-broker Docker example](https://bunqueue.dev/examples/postgres-multibroker/))
|
|
107
130
|
- **BullMQ-compatible API** — same `Queue`, `Worker`, `QueueEvents`; [migrating takes minutes](https://bunqueue.dev/guide/migration/)
|
|
108
131
|
- **MCP server included** — 73 tools; AI agents get full queue control out of the box
|
|
109
132
|
- **Everything server-side** — retries with backoff, priorities, cron, rate limits, dead letter queue
|
|
@@ -111,24 +134,24 @@ Python, PHP, Go, Rust and Elixir clients speak the same protocol — see
|
|
|
111
134
|
in-memory batch push, 186K jobs/sec public on-disk Embedded `addBulk`, and
|
|
112
135
|
159K jobs/sec TCP `PUSHB`; [methodology and distributions](https://bunqueue.dev/guide/benchmarks/)
|
|
113
136
|
|
|
114
|
-
**Great for:** single-server deployments,
|
|
115
|
-
|
|
137
|
+
**Great for:** embedded and single-server deployments, PostgreSQL-backed broker
|
|
138
|
+
fleets, AI agents that need a scheduler, edge/serverless spooling, and teams
|
|
116
139
|
that don't want to operate Redis.
|
|
117
140
|
|
|
118
|
-
**Not ideal for:** multi-region
|
|
119
|
-
|
|
141
|
+
**Not ideal for:** multi-region consensus or deployments that require MySQL as
|
|
142
|
+
the queue store. If you already run Redis and BullMQ works for you, keep it.
|
|
120
143
|
|
|
121
144
|
[When to choose bunqueue →](https://bunqueue.dev/guide/comparison/)
|
|
122
145
|
|
|
123
146
|
## Two Modes
|
|
124
147
|
|
|
125
|
-
| | Embedded
|
|
126
|
-
| ---------------- |
|
|
127
|
-
| **How it works** | Queue runs inside your process
|
|
128
|
-
| **Setup** | `bun add bunqueue`
|
|
129
|
-
| **Performance** | 186K jobs/sec on-disk `addBulk`; 729K internal in-memory batch | 159K
|
|
130
|
-
| **Best for** | Single-process apps, CLIs, serverless
|
|
131
|
-
| **Scaling** | Same process only
|
|
148
|
+
| | Embedded | Server (TCP) |
|
|
149
|
+
| ---------------- | -------------------------------------------------------------- | -------------------------------------------------------- |
|
|
150
|
+
| **How it works** | Queue runs inside your process | Standalone server, clients connect via TCP |
|
|
151
|
+
| **Setup** | `bun add bunqueue` | `docker run` or `bunqueue start` |
|
|
152
|
+
| **Performance** | 186K jobs/sec on-disk `addBulk`; 729K internal in-memory batch | SQLite: 159K TCP `PUSHB`; 17K jobs/sec worker drain |
|
|
153
|
+
| **Best for** | Single-process apps, CLIs, serverless | Multiple workers, separate producer/consumer |
|
|
154
|
+
| **Scaling** | Same process only | Multiple clients; multiple brokers with PostgreSQL 15–18 |
|
|
132
155
|
|
|
133
156
|
### Embedded
|
|
134
157
|
|
|
@@ -180,18 +203,20 @@ await queue.add('process', { data: 'hello' });
|
|
|
180
203
|
|
|
181
204
|
## One Queue, Any Language (SDKs)
|
|
182
205
|
|
|
183
|
-
The server does all the heavy lifting. Official client SDKs
|
|
184
|
-
|
|
185
|
-
anywhere in your stack — add a job from TypeScript, process it
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
|
190
|
-
|
|
|
191
|
-
| **
|
|
192
|
-
| **
|
|
193
|
-
| **
|
|
194
|
-
| **
|
|
206
|
+
The server does all the heavy lifting. Official client SDKs share the
|
|
207
|
+
protocol-conformant core Queue, Worker, and Flow surface, so producers and
|
|
208
|
+
workers can live anywhere in your stack — add a job from TypeScript, process it
|
|
209
|
+
from Python. Language-specific capabilities are tracked in the
|
|
210
|
+
[SDK guide](https://bunqueue.dev/guide/sdks/).
|
|
211
|
+
|
|
212
|
+
| Where your code runs | Install |
|
|
213
|
+
| --------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
214
|
+
| **Node.js ≥ 20, Deno ≥ 2, Bun, Cloudflare Workers** | [`npm install bunqueue-client`](https://www.npmjs.com/package/bunqueue-client) |
|
|
215
|
+
| **Python ≥ 3.9** | [`pip install bunqueue-client`](https://pypi.org/project/bunqueue-client/) |
|
|
216
|
+
| **PHP ≥ 8.1** | [`composer require bunqueue/client`](https://packagist.org/packages/bunqueue/client) |
|
|
217
|
+
| **Go ≥ 1.26.5** | `go get github.com/egeominotti/bunqueue/sdk/go` |
|
|
218
|
+
| **Rust ≥ 1.85** | [`cargo add bunqueue-client`](https://crates.io/crates/bunqueue-client) |
|
|
219
|
+
| **Elixir ≥ 1.15** | Hex coming soon — today: use [`sdk/elixir`](./sdk/elixir) as a path dependency |
|
|
195
220
|
|
|
196
221
|
```typescript
|
|
197
222
|
// Node.js / Deno / Cloudflare Workers
|
|
@@ -237,21 +262,24 @@ const root = await flows.add({
|
|
|
237
262
|
],
|
|
238
263
|
});
|
|
239
264
|
|
|
240
|
-
console.log(
|
|
265
|
+
console.log(
|
|
266
|
+
root.job.id,
|
|
267
|
+
root.children?.map(({ job }) => job.id)
|
|
268
|
+
);
|
|
241
269
|
await flows.close();
|
|
242
270
|
```
|
|
243
271
|
|
|
244
272
|
The repository records the contracts and the test strategy beside each
|
|
245
273
|
implementation:
|
|
246
274
|
|
|
247
|
-
| SDK
|
|
248
|
-
|
|
|
249
|
-
| [TypeScript](./sdk/typescript/README.md) | [contract](./sdk/typescript/INVARIANTS.md) | fast-check
|
|
250
|
-
| [Python](./sdk/python/README.md)
|
|
251
|
-
| [PHP](./sdk/php/README.md)
|
|
252
|
-
| [Go](./sdk/go/README.md)
|
|
253
|
-
| [Rust](./sdk/rust/README.md)
|
|
254
|
-
| [Elixir](./sdk/elixir/README.md)
|
|
275
|
+
| SDK | Runtime invariants | Generated tests | Mutation engine |
|
|
276
|
+
| ---------------------------------------- | ------------------------------------------ | --------------- | --------------- |
|
|
277
|
+
| [TypeScript](./sdk/typescript/README.md) | [contract](./sdk/typescript/INVARIANTS.md) | fast-check | none¹ |
|
|
278
|
+
| [Python](./sdk/python/README.md) | [contract](./sdk/python/INVARIANTS.md) | Hypothesis | mutmut |
|
|
279
|
+
| [PHP](./sdk/php/README.md) | [contract](./sdk/php/INVARIANTS.md) | Eris | Infection |
|
|
280
|
+
| [Go](./sdk/go/README.md) | [contract](./sdk/go/INVARIANTS.md) | Rapid | Gremlins |
|
|
281
|
+
| [Rust](./sdk/rust/README.md) | [contract](./sdk/rust/INVARIANTS.md) | proptest | cargo-mutants |
|
|
282
|
+
| [Elixir](./sdk/elixir/README.md) | [contract](./sdk/elixir/INVARIANTS.md) | StreamData | Muex |
|
|
255
283
|
|
|
256
284
|
¹ The TypeScript SDK has no mutation engine. StrykerJS was removed because its
|
|
257
285
|
dependency graph produced every advisory the weekly audit had to answer for,
|
|
@@ -314,17 +342,25 @@ human-in-the-loop signals — built on bunqueue, no new infrastructure:
|
|
|
314
342
|
import { Workflow, Engine } from 'bunqueue/workflow';
|
|
315
343
|
|
|
316
344
|
const orderFlow = new Workflow('order-pipeline')
|
|
317
|
-
.step(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
345
|
+
.step(
|
|
346
|
+
'reserve-stock',
|
|
347
|
+
async () => {
|
|
348
|
+
await inventory.reserve();
|
|
349
|
+
return { reserved: true };
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
compensate: async () => await inventory.release(), // auto-rollback on failure
|
|
353
|
+
}
|
|
354
|
+
)
|
|
355
|
+
.step(
|
|
356
|
+
'charge',
|
|
357
|
+
async () => {
|
|
358
|
+
return { txId: await payments.charge() };
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
compensate: async () => await payments.refund(),
|
|
362
|
+
}
|
|
363
|
+
)
|
|
328
364
|
.waitFor('manager-approval', { timeout: 86_400_000 }) // human-in-the-loop
|
|
329
365
|
.step('confirm', async (ctx) => {
|
|
330
366
|
return { txId: (ctx.steps['charge'] as { txId: string }).txId };
|
|
@@ -336,13 +372,13 @@ const run = await engine.start('order-pipeline', { orderId: 'ORD-1' });
|
|
|
336
372
|
await engine.signal(run.id, 'manager-approval', { approved: true });
|
|
337
373
|
```
|
|
338
374
|
|
|
339
|
-
|
|
|
340
|
-
|
|
341
|
-
| **Infrastructure**
|
|
342
|
-
| **Saga compensation** | Built-in
|
|
343
|
-
| **Human-in-the-loop** | `.waitFor()`
|
|
344
|
-
| **Self-hosted**
|
|
345
|
-
| **Pricing**
|
|
375
|
+
| | **bunqueue** | **Temporal** | **Inngest** | **Trigger.dev** |
|
|
376
|
+
| --------------------- | --------------- | ----------------------- | --------------------- | ----------------------- |
|
|
377
|
+
| **Infrastructure** | None (embedded) | PostgreSQL + 7 services | Cloud-only | Redis + PostgreSQL |
|
|
378
|
+
| **Saga compensation** | Built-in | Manual | Manual | Manual |
|
|
379
|
+
| **Human-in-the-loop** | `.waitFor()` | Signals API | `step.waitForEvent()` | Waitpoint tokens |
|
|
380
|
+
| **Self-hosted** | Zero-config | Complex | No | Complex |
|
|
381
|
+
| **Pricing** | Free (MIT) | Free / Cloud $$ | Per-execution | Free tier, then $50/mo+ |
|
|
346
382
|
|
|
347
383
|
Also included: nested workflows, `doUntil`/`doWhile` loops, `forEach` over
|
|
348
384
|
dynamic lists, schema validation (Zod, ArkType, Valibot or any `.parse()`),
|
|
@@ -374,8 +410,8 @@ claude mcp add bunqueue -- bunx bunqueue-mcp
|
|
|
374
410
|
}
|
|
375
411
|
```
|
|
376
412
|
|
|
377
|
-
Then just ask:
|
|
378
|
-
failed jobs and retry them"
|
|
413
|
+
Then just ask: _"Schedule a cleanup job every day at 3 AM"_ · _"Show me all
|
|
414
|
+
failed jobs and retry them"_ · _"Set rate limit to 50/sec on api-calls"_.
|
|
379
415
|
|
|
380
416
|
[MCP guide →](https://bunqueue.dev/guide/mcp/)
|
|
381
417
|
|
|
@@ -399,13 +435,13 @@ https://github.com/user-attachments/assets/e8a8d38e-b4a6-4dc8-8360-876c0f24d116
|
|
|
399
435
|
|
|
400
436
|
Native Ryzen 9 9950X3D, Bun 1.3.14; medians from repeated fresh processes:
|
|
401
437
|
|
|
402
|
-
| Workload
|
|
403
|
-
|
|
|
404
|
-
| Internal batched push, 1M jobs
|
|
405
|
-
| Public sustained `addBulk`, 50K cell | Embedded
|
|
406
|
-
| `PUSHB`, fresh 50K sample
|
|
407
|
-
| No-work worker drain, concurrency 50 | TCP
|
|
408
|
-
| Linear Workflow Engine
|
|
438
|
+
| Workload | Mode | Median | Persistence |
|
|
439
|
+
| ------------------------------------ | -------------- | --------------------------: | ------------------------------- |
|
|
440
|
+
| Internal batched push, 1M jobs | Embedded | 729,395 jobs/sec | In-memory, no `dataPath` |
|
|
441
|
+
| Public sustained `addBulk`, 50K cell | Embedded | 186,384 jobs/sec | On-disk buffered SQLite |
|
|
442
|
+
| `PUSHB`, fresh 50K sample | TCP | 158,779 jobs/sec | On-disk buffered SQLite |
|
|
443
|
+
| No-work worker drain, concurrency 50 | TCP | 17,256 jobs/sec | Full pull/process/ACK |
|
|
444
|
+
| Linear Workflow Engine | Embedded / TCP | 2,700 / 3,187 workflows/sec | Workflow SQLite + 3 queue nodes |
|
|
409
445
|
|
|
410
446
|
These operations do different work; the internal in-memory result is not an
|
|
411
447
|
SQLite or public-API claim. Run `bun run bench`, `bun run bench:tcp`, or
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type JobId } from '../../../domain/types/job';
|
|
2
2
|
import type { BackgroundContext } from '../../types';
|
|
3
|
+
export declare function restoreGroupPolicies(ctx: BackgroundContext, groupStates: ReturnType<NonNullable<BackgroundContext['storage']>['loadGroupState']>): void;
|
|
3
4
|
export declare function restoreRecoveryPolicies(ctx: BackgroundContext, queueStates: ReturnType<NonNullable<BackgroundContext['storage']>['loadQueueState']>): void;
|
|
4
5
|
export declare function recoverActiveJobs(ctx: BackgroundContext, dlqJobIds: Set<JobId>, now: number): void;
|
|
@@ -3,6 +3,18 @@ import { calculateBackoff } from '../../../domain/types/job';
|
|
|
3
3
|
import { isCorruptDependsOn } from '../../../infrastructure/persistence/sqliteSerializer';
|
|
4
4
|
import { shardIndex } from '../../../shared/hash';
|
|
5
5
|
import { quarantineCorruptDependsOn, RECOVERY_BATCH_SIZE } from './shared';
|
|
6
|
+
export function restoreGroupPolicies(ctx, groupStates) {
|
|
7
|
+
for (const state of groupStates) {
|
|
8
|
+
const shard = ctx.shards[shardIndex(state.queue)];
|
|
9
|
+
if (state.rateLimit !== null && state.rateDuration !== null) {
|
|
10
|
+
shard.setGroupRateLimit(state.queue, state.groupId, state.rateLimit, state.rateDuration);
|
|
11
|
+
}
|
|
12
|
+
if (state.concurrencyLimit !== null) {
|
|
13
|
+
shard.setGroupConcurrency(state.queue, state.groupId, state.concurrencyLimit);
|
|
14
|
+
}
|
|
15
|
+
ctx.registerQueueName(state.queue);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
6
18
|
export function restoreRecoveryPolicies(ctx, queueStates) {
|
|
7
19
|
for (const queueState of queueStates) {
|
|
8
20
|
if (queueState.stallConfig) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { reconcileDependencyCompletionPins } from '../../dependencyCompletions';
|
|
2
|
-
import { recoverActiveJobs, restoreRecoveryPolicies } from './active';
|
|
2
|
+
import { recoverActiveJobs, restoreGroupPolicies, restoreRecoveryPolicies } from './active';
|
|
3
3
|
import { recoverPendingJobs } from './pending';
|
|
4
4
|
import { recoverCompletedJobs, restoreDlq, restoreQueueState } from './restore';
|
|
5
5
|
export function recover(ctx) {
|
|
@@ -11,7 +11,9 @@ export function recover(ctx) {
|
|
|
11
11
|
completedInDatabase.add(record.jobId);
|
|
12
12
|
const dlqJobIds = ctx.storage.loadDlqJobIds();
|
|
13
13
|
const queueStates = ctx.storage.loadQueueState();
|
|
14
|
+
const groupStates = ctx.storage.loadGroupState();
|
|
14
15
|
restoreRecoveryPolicies(ctx, queueStates);
|
|
16
|
+
restoreGroupPolicies(ctx, groupStates);
|
|
15
17
|
const now = Date.now();
|
|
16
18
|
recoverActiveJobs(ctx, dlqJobIds, now);
|
|
17
19
|
recoverPendingJobs(ctx, completedInDatabase, now);
|
|
@@ -18,6 +18,7 @@ export function recoverPendingJobs(ctx, completedInDatabase, now) {
|
|
|
18
18
|
corruptPendingJobs.push(job);
|
|
19
19
|
continue;
|
|
20
20
|
}
|
|
21
|
+
shard.assignGroupFifoOrder(job);
|
|
21
22
|
const hasDependencies = job.dependsOn && job.dependsOn.length > 0;
|
|
22
23
|
const recoveredState = persistedJobState(job);
|
|
23
24
|
const wasAlreadyPromoted = recoveredState === 'waiting' ||
|
|
@@ -26,7 +26,7 @@ export async function cleanup(ctx) {
|
|
|
26
26
|
}
|
|
27
27
|
await cleanOrphanedProcessingEntries(ctx, now, stallTimeout);
|
|
28
28
|
await cleanStaleWaitingDependencies(ctx, now);
|
|
29
|
-
cleanUniqueKeysAndGroups(ctx);
|
|
29
|
+
cleanUniqueKeysAndGroups(ctx, now);
|
|
30
30
|
cleanStalledCandidates(ctx);
|
|
31
31
|
await cleanOrphanedJobIndex(ctx);
|
|
32
32
|
cleanOrphanedJobLocks(ctx);
|
|
@@ -103,9 +103,10 @@ async function cleanStaleWaitingDependencies(ctx, now) {
|
|
|
103
103
|
}
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
function cleanUniqueKeysAndGroups(ctx) {
|
|
106
|
+
function cleanUniqueKeysAndGroups(ctx, now) {
|
|
107
107
|
for (let i = 0; i < SHARD_COUNT; i++) {
|
|
108
108
|
const shard = ctx.shards[i];
|
|
109
|
+
shard.cleanExpiredGroupWindows(now);
|
|
109
110
|
// Clean expired unique keys
|
|
110
111
|
shard.cleanExpiredUniqueKeys();
|
|
111
112
|
// Trim if too many keys remain
|
|
@@ -121,19 +122,6 @@ function cleanUniqueKeysAndGroups(ctx) {
|
|
|
121
122
|
}
|
|
122
123
|
}
|
|
123
124
|
}
|
|
124
|
-
// Clean orphaned active groups
|
|
125
|
-
for (const [_queueName, groups] of shard.activeGroups) {
|
|
126
|
-
if (groups.size > 1000) {
|
|
127
|
-
const toRemove = Math.floor(groups.size / 2);
|
|
128
|
-
const iter = groups.values();
|
|
129
|
-
for (let j = 0; j < toRemove; j++) {
|
|
130
|
-
const { value, done } = iter.next();
|
|
131
|
-
if (done)
|
|
132
|
-
break;
|
|
133
|
-
groups.delete(value);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
125
|
}
|
|
138
126
|
}
|
|
139
127
|
function cleanStalledCandidates(ctx) {
|
|
@@ -244,7 +232,7 @@ function cleanEmptyQueues(ctx) {
|
|
|
244
232
|
shard.dlq.delete(queueName);
|
|
245
233
|
shard.uniqueKeys.delete(queueName);
|
|
246
234
|
shard.queueState.delete(queueName);
|
|
247
|
-
shard.
|
|
235
|
+
shard.clearEmptyGroupRuntime(queueName);
|
|
248
236
|
shard.clearQueueLimiters(queueName);
|
|
249
237
|
shard.stallConfig.delete(queueName);
|
|
250
238
|
shard.dlqConfig.delete(queueName);
|
|
@@ -102,6 +102,7 @@ export class ContextFactory {
|
|
|
102
102
|
jobIndex: this.deps.jobIndex,
|
|
103
103
|
totalPushed: this.deps.metrics.totalPushed,
|
|
104
104
|
broadcast: this.deps.eventsManager.broadcast.bind(this.deps.eventsManager),
|
|
105
|
+
broadcastBatch: this.deps.eventsManager.broadcastBatch.bind(this.deps.eventsManager),
|
|
105
106
|
dashboardEmit: this.callbacks.emitDashboardEvent,
|
|
106
107
|
registerQueueName: this.callbacks.registerQueueName,
|
|
107
108
|
};
|
|
@@ -116,6 +117,7 @@ export class ContextFactory {
|
|
|
116
117
|
jobIndex: this.deps.jobIndex,
|
|
117
118
|
totalPulled: this.deps.metrics.totalPulled,
|
|
118
119
|
broadcast: this.deps.eventsManager.broadcast.bind(this.deps.eventsManager),
|
|
120
|
+
broadcastBatch: this.deps.eventsManager.broadcastBatch.bind(this.deps.eventsManager),
|
|
119
121
|
dashboardEmit: this.callbacks.emitDashboardEvent,
|
|
120
122
|
};
|
|
121
123
|
}
|
|
@@ -139,6 +141,7 @@ export class ContextFactory {
|
|
|
139
141
|
totalFailed: this.deps.metrics.totalFailed,
|
|
140
142
|
perQueueMetrics: this.deps.perQueueMetrics,
|
|
141
143
|
broadcast: this.deps.eventsManager.broadcast.bind(this.deps.eventsManager),
|
|
144
|
+
broadcastBatch: this.deps.eventsManager.broadcastBatch.bind(this.deps.eventsManager),
|
|
142
145
|
onJobCompleted: this.callbacks.onJobCompleted,
|
|
143
146
|
onJobFailed: this.callbacks.onJobFailed,
|
|
144
147
|
onJobsCompleted: this.callbacks.onJobsCompleted,
|
|
@@ -161,6 +164,7 @@ export class ContextFactory {
|
|
|
161
164
|
jobLocks: this.deps.jobLocks,
|
|
162
165
|
clientJobs: this.deps.clientJobs,
|
|
163
166
|
dependencyResults: this.deps.dependencyResults,
|
|
167
|
+
customIdMap: this.deps.customIdMap,
|
|
164
168
|
depCompletions: this.deps.depCompletions,
|
|
165
169
|
maxDependencyCompletions: this.deps.config.maxCompletedJobs,
|
|
166
170
|
webhookManager: this.deps.webhookManager,
|
|
@@ -188,6 +192,8 @@ export class ContextFactory {
|
|
|
188
192
|
shards: this.deps.shards,
|
|
189
193
|
jobIndex: this.deps.jobIndex,
|
|
190
194
|
jobResults: this.deps.jobResults,
|
|
195
|
+
dependencyResults: this.deps.dependencyResults,
|
|
196
|
+
customIdMap: this.deps.customIdMap,
|
|
191
197
|
jobLogs: this.deps.jobLogs,
|
|
192
198
|
storage: this.deps.storage,
|
|
193
199
|
};
|
|
@@ -201,6 +207,8 @@ export class ContextFactory {
|
|
|
201
207
|
completedJobs: this.deps.completedJobs,
|
|
202
208
|
completedJobsData: this.deps.completedJobsData,
|
|
203
209
|
jobResults: this.deps.jobResults,
|
|
210
|
+
dependencyResults: this.deps.dependencyResults,
|
|
211
|
+
customIdMap: this.deps.customIdMap,
|
|
204
212
|
};
|
|
205
213
|
}
|
|
206
214
|
getLogsContext() {
|
|
@@ -14,6 +14,14 @@ export interface DlqContext {
|
|
|
14
14
|
jobResults: {
|
|
15
15
|
delete(id: JobId): boolean;
|
|
16
16
|
};
|
|
17
|
+
dependencyResults: {
|
|
18
|
+
releaseConsumer(id: JobId): void;
|
|
19
|
+
};
|
|
20
|
+
customIdMap: {
|
|
21
|
+
get(id: string): JobId | undefined;
|
|
22
|
+
set(id: string, jobId: JobId): void;
|
|
23
|
+
delete(id: string): boolean;
|
|
24
|
+
};
|
|
17
25
|
jobLogs: {
|
|
18
26
|
delete(id: JobId): boolean;
|
|
19
27
|
};
|
|
@@ -30,6 +38,8 @@ export declare function getDlqStats(queue: string, ctx: DlqContext): DlqStats;
|
|
|
30
38
|
export declare function purgeExpiredDlq(queue: string, ctx: DlqContext): number;
|
|
31
39
|
/** Purge all jobs from DLQ */
|
|
32
40
|
export declare function purgeDlqJobs(queue: string, ctx: DlqContext): number;
|
|
41
|
+
/** Remove one DLQ entry without re-enqueuing it. */
|
|
42
|
+
export declare function removeDlqJob(queue: string, id: JobId, ctx: DlqContext): boolean;
|
|
33
43
|
/** Configure DLQ for a queue */
|
|
34
44
|
export declare function configureDlq(queue: string, ctx: DlqContext, config: Partial<DlqConfig>): void;
|
|
35
45
|
/** Get DLQ configuration */
|
|
@@ -83,6 +83,40 @@ export function purgeDlqJobs(queue, ctx) {
|
|
|
83
83
|
shard.clearDlq(queue);
|
|
84
84
|
return entries.length;
|
|
85
85
|
}
|
|
86
|
+
/** Remove one DLQ entry without re-enqueuing it. */
|
|
87
|
+
export function removeDlqJob(queue, id, ctx) {
|
|
88
|
+
const shard = ctx.shards[shardIndex(queue)];
|
|
89
|
+
const entries = shard.getDlqEntries(queue).filter((entry) => entry.job.id === id);
|
|
90
|
+
if (entries.length === 0)
|
|
91
|
+
return false;
|
|
92
|
+
const location = ctx.jobIndex.get(id);
|
|
93
|
+
const terminalJobIds = location === undefined || (location.type === 'dlq' && location.queueName === queue) ? [id] : [];
|
|
94
|
+
// Keep the in-memory entry visible until the durable transaction succeeds.
|
|
95
|
+
// This prevents a failed SQLite write from leaving memory and disk out of sync.
|
|
96
|
+
ctx.storage?.purgeDlqEntries(queue, [id], terminalJobIds, false);
|
|
97
|
+
shard.removeAllFromDlq(queue, id);
|
|
98
|
+
cleanupTerminalEntries(queue, entries, terminalJobIds, ctx);
|
|
99
|
+
return true;
|
|
100
|
+
}
|
|
101
|
+
function cleanupTerminalEntries(queue, entries, terminalJobIds, ctx) {
|
|
102
|
+
const terminalIds = new Set(terminalJobIds);
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
if (!terminalIds.has(entry.job.id))
|
|
105
|
+
continue;
|
|
106
|
+
const customId = entry.job.customId;
|
|
107
|
+
if (customId && ctx.customIdMap.get(customId) === entry.job.id) {
|
|
108
|
+
ctx.customIdMap.delete(customId);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const jobId of terminalJobIds) {
|
|
112
|
+
const location = ctx.jobIndex.get(jobId);
|
|
113
|
+
if (location?.type === 'dlq' && location.queueName === queue)
|
|
114
|
+
ctx.jobIndex.delete(jobId);
|
|
115
|
+
ctx.jobResults.delete(jobId);
|
|
116
|
+
ctx.jobLogs.delete(jobId);
|
|
117
|
+
ctx.dependencyResults.releaseConsumer(jobId);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
86
120
|
/** Remove every durable and global reference owned by terminal DLQ entries. */
|
|
87
121
|
function cleanupPurgedEntries(queue, entries, ctx, clearQueue) {
|
|
88
122
|
const jobIds = [...new Set(entries.map((entry) => entry.job.id))];
|
|
@@ -95,14 +129,7 @@ function cleanupPurgedEntries(queue, entries, ctx, clearQueue) {
|
|
|
95
129
|
// A newer live generation can reuse the same custom id; its jobs row and
|
|
96
130
|
// auxiliary state must survive cleanup of the stale terminal generation.
|
|
97
131
|
ctx.storage?.purgeDlqEntries(queue, jobIds, terminalJobIds, clearQueue);
|
|
98
|
-
|
|
99
|
-
const location = ctx.jobIndex.get(jobId);
|
|
100
|
-
if (location?.type === 'dlq' && location.queueName === queue) {
|
|
101
|
-
ctx.jobIndex.delete(jobId);
|
|
102
|
-
}
|
|
103
|
-
ctx.jobResults.delete(jobId);
|
|
104
|
-
ctx.jobLogs.delete(jobId);
|
|
105
|
-
}
|
|
132
|
+
cleanupTerminalEntries(queue, entries, terminalJobIds, ctx);
|
|
106
133
|
}
|
|
107
134
|
/** Configure DLQ for a queue */
|
|
108
135
|
export function configureDlq(queue, ctx, config) {
|
|
@@ -145,6 +172,13 @@ export function retryCompletedJobs(queue, ctx, jobId, options = {}) {
|
|
|
145
172
|
}
|
|
146
173
|
/** Requeue a single completed job */
|
|
147
174
|
function requeueCompletedJob(job, ctx) {
|
|
175
|
+
const currentLocation = ctx.jobIndex.get(job.id);
|
|
176
|
+
if (currentLocation?.type !== 'completed' || currentLocation.queueName !== job.queue)
|
|
177
|
+
return 0;
|
|
178
|
+
const shard = ctx.shards[shardIndex(job.queue)];
|
|
179
|
+
const keyOwner = job.uniqueKey ? shard.getUniqueKeyEntry(job.queue, job.uniqueKey) : null;
|
|
180
|
+
if (keyOwner && keyOwner.jobId !== job.id)
|
|
181
|
+
return 0;
|
|
148
182
|
const now = Date.now();
|
|
149
183
|
const timeline = [...job.timeline];
|
|
150
184
|
if (timeline.length < MAX_TIMELINE_ENTRIES) {
|
|
@@ -162,11 +196,11 @@ function requeueCompletedJob(job, ctx) {
|
|
|
162
196
|
timeline,
|
|
163
197
|
};
|
|
164
198
|
setDlqRetryState(requeued, null);
|
|
199
|
+
shard.assignGroupFifoOrder(requeued);
|
|
165
200
|
// Commit the durable transition before publishing the new in-memory state.
|
|
166
201
|
// A SQLite failure therefore leaves the completed generation authoritative.
|
|
167
202
|
ctx.storage?.requeueCompletedJob(requeued);
|
|
168
203
|
const idx = shardIndex(requeued.queue);
|
|
169
|
-
const shard = ctx.shards[idx];
|
|
170
204
|
shard.getQueue(requeued.queue).push(requeued);
|
|
171
205
|
shard.incrementQueued(requeued.id, false, requeued.createdAt, requeued.queue, requeued.runAt);
|
|
172
206
|
ctx.jobIndex.set(requeued.id, {
|
|
@@ -177,6 +211,11 @@ function requeueCompletedJob(job, ctx) {
|
|
|
177
211
|
ctx.completedJobs.delete(requeued.id);
|
|
178
212
|
ctx.completedJobsData.delete(requeued.id);
|
|
179
213
|
ctx.jobResults.delete(requeued.id);
|
|
214
|
+
if (requeued.customId)
|
|
215
|
+
ctx.customIdMap.set(requeued.customId, requeued.id);
|
|
216
|
+
if (requeued.uniqueKey) {
|
|
217
|
+
shard.registerUniqueKeyWithTtl(requeued.queue, requeued.uniqueKey, requeued.id, requeued.deduplicationTtl ?? undefined);
|
|
218
|
+
}
|
|
180
219
|
shard.notify(requeued.queue);
|
|
181
220
|
return 1;
|
|
182
221
|
}
|