bunqueue 2.8.60 → 2.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +108 -76
- package/dist/application/background/dlq.js +2 -0
- package/dist/application/contextFactory.js +5 -0
- package/dist/application/dlqManager.d.ts +10 -0
- package/dist/application/dlqManager.js +47 -9
- package/dist/application/dlqRetry.js +59 -38
- package/dist/application/eventsManager.d.ts +1 -1
- package/dist/application/eventsManager.js +30 -26
- package/dist/application/operations/jobManagement.d.ts +4 -0
- package/dist/application/operations/jobMoveOperations.js +9 -4
- package/dist/application/postgres-queue-manager/batchSnapshot.d.ts +16 -0
- package/dist/application/postgres-queue-manager/batchSnapshot.js +17 -0
- package/dist/application/postgres-queue-manager/cloud.d.ts +30 -0
- package/dist/application/postgres-queue-manager/cloud.js +55 -0
- package/dist/application/postgres-queue-manager/config.d.ts +5 -0
- package/dist/application/postgres-queue-manager/config.js +1 -0
- package/dist/application/postgres-queue-manager/control.d.ts +26 -0
- package/dist/application/postgres-queue-manager/control.js +186 -0
- package/dist/application/postgres-queue-manager/deferredWrites.d.ts +13 -0
- package/dist/application/postgres-queue-manager/deferredWrites.js +60 -0
- package/dist/application/postgres-queue-manager/delivery.d.ts +19 -0
- package/dist/application/postgres-queue-manager/delivery.js +80 -0
- package/dist/application/postgres-queue-manager/lease.d.ts +13 -0
- package/dist/application/postgres-queue-manager/lease.js +88 -0
- package/dist/application/postgres-queue-manager/lifetimeMetrics.d.ts +32 -0
- package/dist/application/postgres-queue-manager/lifetimeMetrics.js +53 -0
- package/dist/application/postgres-queue-manager/maintenance.d.ts +14 -0
- package/dist/application/postgres-queue-manager/maintenance.js +100 -0
- package/dist/application/postgres-queue-manager/operationGate.d.ts +26 -0
- package/dist/application/postgres-queue-manager/operationGate.js +96 -0
- package/dist/application/postgres-queue-manager/operations.d.ts +25 -0
- package/dist/application/postgres-queue-manager/operations.js +194 -0
- package/dist/application/postgres-queue-manager/projectionRefreshes.d.ts +43 -0
- package/dist/application/postgres-queue-manager/projectionRefreshes.js +170 -0
- package/dist/application/postgres-queue-manager/queries.d.ts +142 -0
- package/dist/application/postgres-queue-manager/queries.js +231 -0
- package/dist/application/postgres-queue-manager/relationships.d.ts +10 -0
- package/dist/application/postgres-queue-manager/relationships.js +45 -0
- package/dist/application/postgres-queue-manager/services.d.ts +31 -0
- package/dist/application/postgres-queue-manager/services.js +149 -0
- package/dist/application/postgres-queue-manager/snapshot.d.ts +51 -0
- package/dist/application/postgres-queue-manager/snapshot.js +236 -0
- package/dist/application/postgres-queue-manager/snapshotViews.d.ts +15 -0
- package/dist/application/postgres-queue-manager/snapshotViews.js +100 -0
- package/dist/application/postgres-queue-manager/startupEventBuffer.d.ts +12 -0
- package/dist/application/postgres-queue-manager/startupEventBuffer.js +36 -0
- package/dist/application/postgres-queue-manager/state.d.ts +47 -0
- package/dist/application/postgres-queue-manager/state.js +273 -0
- package/dist/application/postgres-queue-manager/terminalDelivery.d.ts +20 -0
- package/dist/application/postgres-queue-manager/terminalDelivery.js +100 -0
- package/dist/application/postgresQueueManager.d.ts +2 -0
- package/dist/application/postgresQueueManager.js +1 -0
- package/dist/application/queue-manager/flow-failures.js +4 -0
- package/dist/application/queue-manager/limits.d.ts +2 -0
- package/dist/application/queue-manager/limits.js +4 -0
- package/dist/application/queue-manager/observability.js +15 -3
- package/dist/application/queue-manager/queries.d.ts +7 -0
- package/dist/application/queue-manager/queries.js +9 -0
- package/dist/application/queue-manager/services.d.ts +1 -1
- package/dist/application/queue-manager/services.js +4 -2
- package/dist/application/queue-manager/state.js +16 -1
- package/dist/cli/commands/server.js +1 -1
- package/dist/client/forwarder.d.ts +6 -4
- package/dist/client/forwarder.js +5 -3
- package/dist/client/queue/dlq.d.ts +2 -0
- package/dist/client/queue/dlq.js +14 -0
- package/dist/client/queue/dlqOps.d.ts +2 -0
- package/dist/client/queue/dlqOps.js +4 -0
- package/dist/client/queue/helpers.js +2 -0
- package/dist/client/queue/runtime/configuration.d.ts +4 -0
- package/dist/client/queue/runtime/configuration.js +8 -0
- package/dist/client/worker/runtime/execution.js +3 -8
- package/dist/client/worker/runtime/polling.d.ts +1 -0
- package/dist/client/worker/runtime/polling.js +9 -0
- package/dist/config/resolve.d.ts +14 -0
- package/dist/config/resolve.js +50 -5
- package/dist/config/types.d.ts +18 -0
- package/dist/domain/queue/dlqShard.d.ts +2 -0
- package/dist/domain/queue/dlqShard.js +16 -0
- package/dist/domain/queue/shard/dlq.d.ts +1 -0
- package/dist/domain/queue/shard/dlq.js +3 -0
- package/dist/domain/types/commands/dlq.d.ts +5 -0
- package/dist/domain/types/commands/union.d.ts +1 -1
- package/dist/domain/types/cron.d.ts +5 -0
- package/dist/domain/types/cron.js +14 -3
- package/dist/domain/types/dlq.d.ts +1 -1
- package/dist/domain/types/dlq.js +1 -2
- package/dist/domain/types/jobs/model.d.ts +1 -1
- package/dist/infrastructure/cloud/commandHandler.js +5 -3
- package/dist/infrastructure/cloud/commands/integrations.js +11 -11
- package/dist/infrastructure/cloud/commands/jobs.js +48 -40
- package/dist/infrastructure/cloud/commands/queues.js +61 -75
- package/dist/infrastructure/cloud/queueAdapter/local.d.ts +41 -0
- package/dist/infrastructure/cloud/queueAdapter/local.js +187 -0
- package/dist/infrastructure/cloud/queueAdapter/postgres.d.ts +42 -0
- package/dist/infrastructure/cloud/queueAdapter/postgres.js +188 -0
- package/dist/infrastructure/cloud/queueAdapter/registry.d.ts +4 -0
- package/dist/infrastructure/cloud/queueAdapter/registry.js +15 -0
- package/dist/infrastructure/cloud/queueAdapter/types.d.ts +87 -0
- package/dist/infrastructure/cloud/queueAdapter/types.js +1 -0
- package/dist/infrastructure/cloud/snapshot/analytics.d.ts +2 -0
- package/dist/infrastructure/cloud/snapshot/analytics.js +7 -0
- package/dist/infrastructure/cloud/snapshot/collector.d.ts +4 -0
- package/dist/infrastructure/cloud/snapshot/collector.js +39 -1
- package/dist/infrastructure/cloud/snapshot/config.d.ts +3 -0
- package/dist/infrastructure/cloud/snapshot/config.js +43 -0
- package/dist/infrastructure/cloud/snapshot/jobs.d.ts +3 -0
- package/dist/infrastructure/cloud/snapshot/jobs.js +32 -1
- package/dist/infrastructure/cloud/snapshotCollector.js +20 -35
- package/dist/infrastructure/cloud/snapshotHelpers.d.ts +3 -3
- package/dist/infrastructure/cloud/snapshotHelpers.js +3 -3
- package/dist/infrastructure/cloud/statsRefresh.js +2 -1
- package/dist/infrastructure/cloud/types/command.d.ts +2 -2
- package/dist/infrastructure/persistence/postgres/admission.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/admission.js +193 -0
- package/dist/infrastructure/persistence/postgres/admissionParent.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/admissionParent.js +35 -0
- package/dist/infrastructure/persistence/postgres/admissionResult.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/admissionResult.js +1 -0
- package/dist/infrastructure/persistence/postgres/admissionStore.d.ts +12 -0
- package/dist/infrastructure/persistence/postgres/admissionStore.js +101 -0
- package/dist/infrastructure/persistence/postgres/advisoryLocks.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres/advisoryLocks.js +13 -0
- package/dist/infrastructure/persistence/postgres/batchAdmission.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/batchAdmission.js +110 -0
- package/dist/infrastructure/persistence/postgres/batchCompletion.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/batchCompletion.js +174 -0
- package/dist/infrastructure/persistence/postgres/batchEvents.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/batchEvents.js +72 -0
- package/dist/infrastructure/persistence/postgres/brokerSessions.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/brokerSessions.js +94 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/claimBatch.js +56 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/claimSelection.js +198 -0
- package/dist/infrastructure/persistence/postgres/claims.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/claims.js +137 -0
- package/dist/infrastructure/persistence/postgres/cloudReadModel.d.ts +26 -0
- package/dist/infrastructure/persistence/postgres/cloudReadModel.js +123 -0
- package/dist/infrastructure/persistence/postgres/codec.d.ts +30 -0
- package/dist/infrastructure/persistence/postgres/codec.js +82 -0
- package/dist/infrastructure/persistence/postgres/completionEvents.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/completionEvents.js +21 -0
- package/dist/infrastructure/persistence/postgres/completionLifecycle.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/completionLifecycle.js +145 -0
- package/dist/infrastructure/persistence/postgres/completionOutcome.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/completionOutcome.js +112 -0
- package/dist/infrastructure/persistence/postgres/completionQueries.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/completionQueries.js +87 -0
- package/dist/infrastructure/persistence/postgres/connection.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/connection.js +15 -0
- package/dist/infrastructure/persistence/postgres/context.d.ts +28 -0
- package/dist/infrastructure/persistence/postgres/context.js +74 -0
- package/dist/infrastructure/persistence/postgres/control.d.ts +23 -0
- package/dist/infrastructure/persistence/postgres/control.js +105 -0
- package/dist/infrastructure/persistence/postgres/crons.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/crons.js +205 -0
- package/dist/infrastructure/persistence/postgres/deduplication.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/deduplication.js +47 -0
- package/dist/infrastructure/persistence/postgres/dependencyDestruction.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/dependencyDestruction.js +74 -0
- package/dist/infrastructure/persistence/postgres/dependencyPromotion.d.ts +29 -0
- package/dist/infrastructure/persistence/postgres/dependencyPromotion.js +212 -0
- package/dist/infrastructure/persistence/postgres/destructiveMutations.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/destructiveMutations.js +111 -0
- package/dist/infrastructure/persistence/postgres/dlqLifecycle.d.ts +13 -0
- package/dist/infrastructure/persistence/postgres/dlqLifecycle.js +184 -0
- package/dist/infrastructure/persistence/postgres/dlqMaintenance.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/dlqMaintenance.js +36 -0
- package/dist/infrastructure/persistence/postgres/dlqRetryPlan.d.ts +21 -0
- package/dist/infrastructure/persistence/postgres/dlqRetryPlan.js +92 -0
- package/dist/infrastructure/persistence/postgres/eventCommitGc.d.ts +27 -0
- package/dist/infrastructure/persistence/postgres/eventCommitGc.js +62 -0
- package/dist/infrastructure/persistence/postgres/eventJournal.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/eventJournal.js +76 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/eventJournalSchema.js +253 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.d.ts +24 -0
- package/dist/infrastructure/persistence/postgres/eventPruneWatermarks.js +111 -0
- package/dist/infrastructure/persistence/postgres/eventRetention.d.ts +18 -0
- package/dist/infrastructure/persistence/postgres/eventRetention.js +76 -0
- package/dist/infrastructure/persistence/postgres/events.d.ts +45 -0
- package/dist/infrastructure/persistence/postgres/events.js +249 -0
- package/dist/infrastructure/persistence/postgres/expiry.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/expiry.js +74 -0
- package/dist/infrastructure/persistence/postgres/flowFailures.d.ts +17 -0
- package/dist/infrastructure/persistence/postgres/flowFailures.js +199 -0
- package/dist/infrastructure/persistence/postgres/jobData.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/jobData.js +32 -0
- package/dist/infrastructure/persistence/postgres/leaseRelease.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/leaseRelease.js +120 -0
- package/dist/infrastructure/persistence/postgres/leaseRenewal.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/leaseRenewal.js +35 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetrics.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetrics.js +46 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/lifetimeMetricsFinalizer.js +13 -0
- package/dist/infrastructure/persistence/postgres/logs.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/logs.js +70 -0
- package/dist/infrastructure/persistence/postgres/maintenance.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/maintenance.js +138 -0
- package/dist/infrastructure/persistence/postgres/maintenanceFlights.d.ts +14 -0
- package/dist/infrastructure/persistence/postgres/maintenanceFlights.js +66 -0
- package/dist/infrastructure/persistence/postgres/metricWrites.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/metricWrites.js +94 -0
- package/dist/infrastructure/persistence/postgres/mutations.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/mutations.js +171 -0
- package/dist/infrastructure/persistence/postgres/outcomes.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/outcomes.js +194 -0
- package/dist/infrastructure/persistence/postgres/policies.d.ts +11 -0
- package/dist/infrastructure/persistence/postgres/policies.js +18 -0
- package/dist/infrastructure/persistence/postgres/postCommitMaintenance.d.ts +17 -0
- package/dist/infrastructure/persistence/postgres/postCommitMaintenance.js +117 -0
- package/dist/infrastructure/persistence/postgres/promotion.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/promotion.js +43 -0
- package/dist/infrastructure/persistence/postgres/queries.d.ts +22 -0
- package/dist/infrastructure/persistence/postgres/queries.js +152 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/queueDestruction.js +154 -0
- package/dist/infrastructure/persistence/postgres/queueLifecycle.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/queueLifecycle.js +60 -0
- package/dist/infrastructure/persistence/postgres/rateLimit.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/rateLimit.js +10 -0
- package/dist/infrastructure/persistence/postgres/readModels.d.ts +32 -0
- package/dist/infrastructure/persistence/postgres/readModels.js +72 -0
- package/dist/infrastructure/persistence/postgres/recovery.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/recovery.js +178 -0
- package/dist/infrastructure/persistence/postgres/relationships.d.ts +9 -0
- package/dist/infrastructure/persistence/postgres/relationships.js +201 -0
- package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/removeUnprocessedChildren.js +241 -0
- package/dist/infrastructure/persistence/postgres/repeatMutations.d.ts +5 -0
- package/dist/infrastructure/persistence/postgres/repeatMutations.js +37 -0
- package/dist/infrastructure/persistence/postgres/runtime.d.ts +46 -0
- package/dist/infrastructure/persistence/postgres/runtime.js +236 -0
- package/dist/infrastructure/persistence/postgres/runtimeConfig.d.ts +21 -0
- package/dist/infrastructure/persistence/postgres/runtimeConfig.js +39 -0
- package/dist/infrastructure/persistence/postgres/schema.d.ts +4 -0
- package/dist/infrastructure/persistence/postgres/schema.js +257 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/schemaInitialization.js +221 -0
- package/dist/infrastructure/persistence/postgres/serialAdmission.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/serialAdmission.js +96 -0
- package/dist/infrastructure/persistence/postgres/snapshotBudget.d.ts +3 -0
- package/dist/infrastructure/persistence/postgres/snapshotBudget.js +83 -0
- package/dist/infrastructure/persistence/postgres/storageHealth.d.ts +10 -0
- package/dist/infrastructure/persistence/postgres/storageHealth.js +29 -0
- package/dist/infrastructure/persistence/postgres/store.d.ts +90 -0
- package/dist/infrastructure/persistence/postgres/store.js +136 -0
- package/dist/infrastructure/persistence/postgres/telemetry.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/telemetry.js +88 -0
- package/dist/infrastructure/persistence/postgres/terminal.d.ts +8 -0
- package/dist/infrastructure/persistence/postgres/terminal.js +137 -0
- package/dist/infrastructure/persistence/postgres/transactionRetry.d.ts +6 -0
- package/dist/infrastructure/persistence/postgres/transactionRetry.js +42 -0
- package/dist/infrastructure/persistence/postgres/types.d.ts +175 -0
- package/dist/infrastructure/persistence/postgres/types.js +1 -0
- package/dist/infrastructure/persistence/postgres/workers.d.ts +15 -0
- package/dist/infrastructure/persistence/postgres/workers.js +126 -0
- package/dist/infrastructure/persistence/postgres.d.ts +2 -0
- package/dist/infrastructure/persistence/postgres.js +1 -0
- package/dist/infrastructure/persistence/sqlite/jobs.js +2 -0
- package/dist/infrastructure/scheduler/cron/persisted.d.ts +5 -0
- package/dist/infrastructure/scheduler/cron/persisted.js +27 -0
- package/dist/infrastructure/scheduler/cron/runtime.js +5 -10
- package/dist/infrastructure/scheduler/cron/validation.d.ts +3 -0
- package/dist/infrastructure/scheduler/cron/validation.js +11 -0
- package/dist/infrastructure/scheduler/cronParser.d.ts +1 -1
- package/dist/infrastructure/scheduler/cronParser.js +144 -11
- package/dist/infrastructure/server/bootstrap.d.ts +2 -3
- package/dist/infrastructure/server/bootstrap.js +33 -59
- package/dist/infrastructure/server/errors.d.ts +4 -0
- package/dist/infrastructure/server/errors.js +54 -0
- package/dist/infrastructure/server/handler-routes/control.d.ts +5 -5
- package/dist/infrastructure/server/handler-routes/control.js +3 -1
- package/dist/infrastructure/server/handler-routes/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.js +32 -31
- package/dist/infrastructure/server/handlers/cron.d.ts +4 -4
- package/dist/infrastructure/server/handlers/cron.js +60 -59
- package/dist/infrastructure/server/handlers/dashboard.d.ts +1 -1
- package/dist/infrastructure/server/handlers/dashboard.js +21 -8
- package/dist/infrastructure/server/handlers/dlq.d.ts +6 -3
- package/dist/infrastructure/server/handlers/dlq.js +35 -9
- package/dist/infrastructure/server/handlers/flow.js +2 -1
- package/dist/infrastructure/server/handlers/management.d.ts +5 -5
- package/dist/infrastructure/server/handlers/management.js +36 -9
- package/dist/infrastructure/server/handlers/monitoring/health.d.ts +5 -5
- package/dist/infrastructure/server/handlers/monitoring/health.js +45 -16
- package/dist/infrastructure/server/handlers/monitoring/operations.d.ts +1 -1
- package/dist/infrastructure/server/handlers/monitoring/operations.js +8 -1
- package/dist/infrastructure/server/handlers/monitoring/workers.d.ts +3 -3
- package/dist/infrastructure/server/handlers/monitoring/workers.js +31 -7
- package/dist/infrastructure/server/handlers/pushBatchValidation.d.ts +3 -1
- package/dist/infrastructure/server/handlers/pushBatchValidation.js +52 -7
- package/dist/infrastructure/server/handlers/query.d.ts +1 -1
- package/dist/infrastructure/server/handlers/query.js +5 -4
- package/dist/infrastructure/server/http.js +2 -2
- package/dist/infrastructure/server/httpDashboardEndpoints.d.ts +1 -1
- package/dist/infrastructure/server/httpDashboardEndpoints.js +19 -6
- package/dist/infrastructure/server/httpEndpoints.js +18 -7
- package/dist/infrastructure/server/httpRouteQueues.js +11 -1
- package/dist/infrastructure/server/shutdownCoordinator.d.ts +24 -0
- package/dist/infrastructure/server/shutdownCoordinator.js +106 -0
- package/dist/infrastructure/server/sseHandler.js +8 -3
- package/dist/infrastructure/server/storageAdapter.d.ts +29 -0
- package/dist/infrastructure/server/storageAdapter.js +61 -0
- package/dist/infrastructure/server/storageManager.d.ts +12 -0
- package/dist/infrastructure/server/storageManager.js +102 -0
- package/dist/infrastructure/server/tcp.js +2 -3
- package/dist/infrastructure/server/ws/snapshots.d.ts +1 -1
- package/dist/infrastructure/server/ws/snapshots.js +19 -4
- package/dist/infrastructure/server/wsHandler.js +10 -5
- package/dist/main.js +1 -1
- package/dist/mcp/backend/embedded/services.js +2 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.js +2 -2
- package/dist/shared/storageHealth.d.ts +9 -0
- package/dist/shared/storageHealth.js +12 -0
- package/package.json +74 -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,8 +66,24 @@ docker run -d -p 6789:6789 -p 6790:6790 \
|
|
|
67
66
|
ghcr.io/egeominotti/bunqueue:latest
|
|
68
67
|
```
|
|
69
68
|
|
|
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
|
+
|
|
70
85
|
Release images also carry the exact package version. For reproducible
|
|
71
|
-
deployments, pin `ghcr.io/egeominotti/bunqueue:2.
|
|
86
|
+
deployments, pin `ghcr.io/egeominotti/bunqueue:2.9.0`; `latest` points to the
|
|
72
87
|
same multi-arch image at release time.
|
|
73
88
|
|
|
74
89
|
Then produce and process from the language you already use:
|
|
@@ -80,7 +95,7 @@ npm install bunqueue-client # Node.js ≥ 20, Deno ≥ 2, Bun, Cloudflare Wor
|
|
|
80
95
|
```typescript
|
|
81
96
|
import { Queue, Worker } from 'bunqueue-client';
|
|
82
97
|
|
|
83
|
-
const queue = new Queue('emails');
|
|
98
|
+
const queue = new Queue('emails'); // localhost:6789 by default
|
|
84
99
|
await queue.add('welcome', { to: 'user@example.com' });
|
|
85
100
|
|
|
86
101
|
new Worker('emails', async (job) => ({ sent: true }), { concurrency: 10 });
|
|
@@ -96,14 +111,18 @@ Python, PHP, Go, Rust and Elixir clients speak the same protocol — see
|
|
|
96
111
|
|
|
97
112
|
## Why bunqueue?
|
|
98
113
|
|
|
99
|
-
| Library | Requires
|
|
100
|
-
| ------------ |
|
|
101
|
-
| BullMQ | Redis
|
|
102
|
-
| Agenda | MongoDB
|
|
103
|
-
| pg-boss | PostgreSQL
|
|
104
|
-
| **bunqueue** | **Nothing** | **Yes** |
|
|
105
|
-
|
|
106
|
-
- **Zero external infrastructure** —
|
|
114
|
+
| Library | Requires | AI-native |
|
|
115
|
+
| ------------ | ------------------------------------------ | --------- |
|
|
116
|
+
| BullMQ | Redis | No |
|
|
117
|
+
| Agenda | MongoDB | No |
|
|
118
|
+
| pg-boss | PostgreSQL | No |
|
|
119
|
+
| **bunqueue** | **Nothing (memory/SQLite) · PostgreSQL optional** | **Yes** |
|
|
120
|
+
|
|
121
|
+
- **Zero external infrastructure by default** — memory by default; one SQLite
|
|
122
|
+
file when local persistence is configured
|
|
123
|
+
- **PostgreSQL 15–18 multi-broker mode** — PostgreSQL 18.6 is recommended;
|
|
124
|
+
database-authoritative claims, fenced
|
|
125
|
+
leases, shared limits, cron, workers, job-state/lifecycle metrics, and failover state
|
|
107
126
|
- **BullMQ-compatible API** — same `Queue`, `Worker`, `QueueEvents`; [migrating takes minutes](https://bunqueue.dev/guide/migration/)
|
|
108
127
|
- **MCP server included** — 73 tools; AI agents get full queue control out of the box
|
|
109
128
|
- **Everything server-side** — retries with backoff, priorities, cron, rate limits, dead letter queue
|
|
@@ -111,24 +130,24 @@ Python, PHP, Go, Rust and Elixir clients speak the same protocol — see
|
|
|
111
130
|
in-memory batch push, 186K jobs/sec public on-disk Embedded `addBulk`, and
|
|
112
131
|
159K jobs/sec TCP `PUSHB`; [methodology and distributions](https://bunqueue.dev/guide/benchmarks/)
|
|
113
132
|
|
|
114
|
-
**Great for:** single-server deployments,
|
|
115
|
-
|
|
133
|
+
**Great for:** embedded and single-server deployments, PostgreSQL-backed broker
|
|
134
|
+
fleets, AI agents that need a scheduler, edge/serverless spooling, and teams
|
|
116
135
|
that don't want to operate Redis.
|
|
117
136
|
|
|
118
|
-
**Not ideal for:** multi-region
|
|
119
|
-
|
|
137
|
+
**Not ideal for:** multi-region consensus or deployments that require MySQL as
|
|
138
|
+
the queue store. If you already run Redis and BullMQ works for you, keep it.
|
|
120
139
|
|
|
121
140
|
[When to choose bunqueue →](https://bunqueue.dev/guide/comparison/)
|
|
122
141
|
|
|
123
142
|
## Two Modes
|
|
124
143
|
|
|
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
|
|
144
|
+
| | Embedded | Server (TCP) |
|
|
145
|
+
| ---------------- | -------------------------------------------------------------- | -------------------------------------------------------- |
|
|
146
|
+
| **How it works** | Queue runs inside your process | Standalone server, clients connect via TCP |
|
|
147
|
+
| **Setup** | `bun add bunqueue` | `docker run` or `bunqueue start` |
|
|
148
|
+
| **Performance** | 186K jobs/sec on-disk `addBulk`; 729K internal in-memory batch | SQLite: 159K TCP `PUSHB`; 17K jobs/sec worker drain |
|
|
149
|
+
| **Best for** | Single-process apps, CLIs, serverless | Multiple workers, separate producer/consumer |
|
|
150
|
+
| **Scaling** | Same process only | Multiple clients; multiple brokers with PostgreSQL 15–18 |
|
|
132
151
|
|
|
133
152
|
### Embedded
|
|
134
153
|
|
|
@@ -180,18 +199,20 @@ await queue.add('process', { data: 'hello' });
|
|
|
180
199
|
|
|
181
200
|
## One Queue, Any Language (SDKs)
|
|
182
201
|
|
|
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
|
-
| **
|
|
202
|
+
The server does all the heavy lifting. Official client SDKs share the
|
|
203
|
+
protocol-conformant core Queue, Worker, and Flow surface, so producers and
|
|
204
|
+
workers can live anywhere in your stack — add a job from TypeScript, process it
|
|
205
|
+
from Python. Language-specific capabilities are tracked in the
|
|
206
|
+
[SDK guide](https://bunqueue.dev/guide/sdks/).
|
|
207
|
+
|
|
208
|
+
| Where your code runs | Install |
|
|
209
|
+
| --------------------------------------------------- | -------------------------------------------------------------------------------------- |
|
|
210
|
+
| **Node.js ≥ 20, Deno ≥ 2, Bun, Cloudflare Workers** | [`npm install bunqueue-client`](https://www.npmjs.com/package/bunqueue-client) |
|
|
211
|
+
| **Python ≥ 3.9** | [`pip install bunqueue-client`](https://pypi.org/project/bunqueue-client/) |
|
|
212
|
+
| **PHP ≥ 8.1** | [`composer require bunqueue/client`](https://packagist.org/packages/bunqueue/client) |
|
|
213
|
+
| **Go ≥ 1.26.5** | `go get github.com/egeominotti/bunqueue/sdk/go` |
|
|
214
|
+
| **Rust ≥ 1.85** | [`cargo add bunqueue-client`](https://crates.io/crates/bunqueue-client) |
|
|
215
|
+
| **Elixir ≥ 1.15** | Hex coming soon — today: use [`sdk/elixir`](./sdk/elixir) as a path dependency |
|
|
195
216
|
|
|
196
217
|
```typescript
|
|
197
218
|
// Node.js / Deno / Cloudflare Workers
|
|
@@ -237,21 +258,24 @@ const root = await flows.add({
|
|
|
237
258
|
],
|
|
238
259
|
});
|
|
239
260
|
|
|
240
|
-
console.log(
|
|
261
|
+
console.log(
|
|
262
|
+
root.job.id,
|
|
263
|
+
root.children?.map(({ job }) => job.id)
|
|
264
|
+
);
|
|
241
265
|
await flows.close();
|
|
242
266
|
```
|
|
243
267
|
|
|
244
268
|
The repository records the contracts and the test strategy beside each
|
|
245
269
|
implementation:
|
|
246
270
|
|
|
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)
|
|
271
|
+
| SDK | Runtime invariants | Generated tests | Mutation engine |
|
|
272
|
+
| ---------------------------------------- | ------------------------------------------ | --------------- | --------------- |
|
|
273
|
+
| [TypeScript](./sdk/typescript/README.md) | [contract](./sdk/typescript/INVARIANTS.md) | fast-check | none¹ |
|
|
274
|
+
| [Python](./sdk/python/README.md) | [contract](./sdk/python/INVARIANTS.md) | Hypothesis | mutmut |
|
|
275
|
+
| [PHP](./sdk/php/README.md) | [contract](./sdk/php/INVARIANTS.md) | Eris | Infection |
|
|
276
|
+
| [Go](./sdk/go/README.md) | [contract](./sdk/go/INVARIANTS.md) | Rapid | Gremlins |
|
|
277
|
+
| [Rust](./sdk/rust/README.md) | [contract](./sdk/rust/INVARIANTS.md) | proptest | cargo-mutants |
|
|
278
|
+
| [Elixir](./sdk/elixir/README.md) | [contract](./sdk/elixir/INVARIANTS.md) | StreamData | Muex |
|
|
255
279
|
|
|
256
280
|
¹ The TypeScript SDK has no mutation engine. StrykerJS was removed because its
|
|
257
281
|
dependency graph produced every advisory the weekly audit had to answer for,
|
|
@@ -314,17 +338,25 @@ human-in-the-loop signals — built on bunqueue, no new infrastructure:
|
|
|
314
338
|
import { Workflow, Engine } from 'bunqueue/workflow';
|
|
315
339
|
|
|
316
340
|
const orderFlow = new Workflow('order-pipeline')
|
|
317
|
-
.step(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
341
|
+
.step(
|
|
342
|
+
'reserve-stock',
|
|
343
|
+
async () => {
|
|
344
|
+
await inventory.reserve();
|
|
345
|
+
return { reserved: true };
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
compensate: async () => await inventory.release(), // auto-rollback on failure
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
.step(
|
|
352
|
+
'charge',
|
|
353
|
+
async () => {
|
|
354
|
+
return { txId: await payments.charge() };
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
compensate: async () => await payments.refund(),
|
|
358
|
+
}
|
|
359
|
+
)
|
|
328
360
|
.waitFor('manager-approval', { timeout: 86_400_000 }) // human-in-the-loop
|
|
329
361
|
.step('confirm', async (ctx) => {
|
|
330
362
|
return { txId: (ctx.steps['charge'] as { txId: string }).txId };
|
|
@@ -336,13 +368,13 @@ const run = await engine.start('order-pipeline', { orderId: 'ORD-1' });
|
|
|
336
368
|
await engine.signal(run.id, 'manager-approval', { approved: true });
|
|
337
369
|
```
|
|
338
370
|
|
|
339
|
-
|
|
|
340
|
-
|
|
341
|
-
| **Infrastructure**
|
|
342
|
-
| **Saga compensation** | Built-in
|
|
343
|
-
| **Human-in-the-loop** | `.waitFor()`
|
|
344
|
-
| **Self-hosted**
|
|
345
|
-
| **Pricing**
|
|
371
|
+
| | **bunqueue** | **Temporal** | **Inngest** | **Trigger.dev** |
|
|
372
|
+
| --------------------- | --------------- | ----------------------- | --------------------- | ----------------------- |
|
|
373
|
+
| **Infrastructure** | None (embedded) | PostgreSQL + 7 services | Cloud-only | Redis + PostgreSQL |
|
|
374
|
+
| **Saga compensation** | Built-in | Manual | Manual | Manual |
|
|
375
|
+
| **Human-in-the-loop** | `.waitFor()` | Signals API | `step.waitForEvent()` | Waitpoint tokens |
|
|
376
|
+
| **Self-hosted** | Zero-config | Complex | No | Complex |
|
|
377
|
+
| **Pricing** | Free (MIT) | Free / Cloud $$ | Per-execution | Free tier, then $50/mo+ |
|
|
346
378
|
|
|
347
379
|
Also included: nested workflows, `doUntil`/`doWhile` loops, `forEach` over
|
|
348
380
|
dynamic lists, schema validation (Zod, ArkType, Valibot or any `.parse()`),
|
|
@@ -374,8 +406,8 @@ claude mcp add bunqueue -- bunx bunqueue-mcp
|
|
|
374
406
|
}
|
|
375
407
|
```
|
|
376
408
|
|
|
377
|
-
Then just ask:
|
|
378
|
-
failed jobs and retry them"
|
|
409
|
+
Then just ask: _"Schedule a cleanup job every day at 3 AM"_ · _"Show me all
|
|
410
|
+
failed jobs and retry them"_ · _"Set rate limit to 50/sec on api-calls"_.
|
|
379
411
|
|
|
380
412
|
[MCP guide →](https://bunqueue.dev/guide/mcp/)
|
|
381
413
|
|
|
@@ -399,13 +431,13 @@ https://github.com/user-attachments/assets/e8a8d38e-b4a6-4dc8-8360-876c0f24d116
|
|
|
399
431
|
|
|
400
432
|
Native Ryzen 9 9950X3D, Bun 1.3.14; medians from repeated fresh processes:
|
|
401
433
|
|
|
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
|
|
434
|
+
| Workload | Mode | Median | Persistence |
|
|
435
|
+
| ------------------------------------ | -------------- | --------------------------: | ------------------------------- |
|
|
436
|
+
| Internal batched push, 1M jobs | Embedded | 729,395 jobs/sec | In-memory, no `dataPath` |
|
|
437
|
+
| Public sustained `addBulk`, 50K cell | Embedded | 186,384 jobs/sec | On-disk buffered SQLite |
|
|
438
|
+
| `PUSHB`, fresh 50K sample | TCP | 158,779 jobs/sec | On-disk buffered SQLite |
|
|
439
|
+
| No-work worker drain, concurrency 50 | TCP | 17,256 jobs/sec | Full pull/process/ACK |
|
|
440
|
+
| Linear Workflow Engine | Embedded / TCP | 2,700 / 3,187 workflows/sec | Workflow SQLite + 3 queue nodes |
|
|
409
441
|
|
|
410
442
|
These operations do different work; the internal in-memory result is not an
|
|
411
443
|
SQLite or public-API claim. Run `bun run bench`, `bun run bench:tcp`, or
|
|
@@ -161,6 +161,7 @@ export class ContextFactory {
|
|
|
161
161
|
jobLocks: this.deps.jobLocks,
|
|
162
162
|
clientJobs: this.deps.clientJobs,
|
|
163
163
|
dependencyResults: this.deps.dependencyResults,
|
|
164
|
+
customIdMap: this.deps.customIdMap,
|
|
164
165
|
depCompletions: this.deps.depCompletions,
|
|
165
166
|
maxDependencyCompletions: this.deps.config.maxCompletedJobs,
|
|
166
167
|
webhookManager: this.deps.webhookManager,
|
|
@@ -188,6 +189,8 @@ export class ContextFactory {
|
|
|
188
189
|
shards: this.deps.shards,
|
|
189
190
|
jobIndex: this.deps.jobIndex,
|
|
190
191
|
jobResults: this.deps.jobResults,
|
|
192
|
+
dependencyResults: this.deps.dependencyResults,
|
|
193
|
+
customIdMap: this.deps.customIdMap,
|
|
191
194
|
jobLogs: this.deps.jobLogs,
|
|
192
195
|
storage: this.deps.storage,
|
|
193
196
|
};
|
|
@@ -201,6 +204,8 @@ export class ContextFactory {
|
|
|
201
204
|
completedJobs: this.deps.completedJobs,
|
|
202
205
|
completedJobsData: this.deps.completedJobsData,
|
|
203
206
|
jobResults: this.deps.jobResults,
|
|
207
|
+
dependencyResults: this.deps.dependencyResults,
|
|
208
|
+
customIdMap: this.deps.customIdMap,
|
|
204
209
|
};
|
|
205
210
|
}
|
|
206
211
|
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) {
|
|
@@ -166,7 +200,6 @@ function requeueCompletedJob(job, ctx) {
|
|
|
166
200
|
// A SQLite failure therefore leaves the completed generation authoritative.
|
|
167
201
|
ctx.storage?.requeueCompletedJob(requeued);
|
|
168
202
|
const idx = shardIndex(requeued.queue);
|
|
169
|
-
const shard = ctx.shards[idx];
|
|
170
203
|
shard.getQueue(requeued.queue).push(requeued);
|
|
171
204
|
shard.incrementQueued(requeued.id, false, requeued.createdAt, requeued.queue, requeued.runAt);
|
|
172
205
|
ctx.jobIndex.set(requeued.id, {
|
|
@@ -177,6 +210,11 @@ function requeueCompletedJob(job, ctx) {
|
|
|
177
210
|
ctx.completedJobs.delete(requeued.id);
|
|
178
211
|
ctx.completedJobsData.delete(requeued.id);
|
|
179
212
|
ctx.jobResults.delete(requeued.id);
|
|
213
|
+
if (requeued.customId)
|
|
214
|
+
ctx.customIdMap.set(requeued.customId, requeued.id);
|
|
215
|
+
if (requeued.uniqueKey) {
|
|
216
|
+
shard.registerUniqueKeyWithTtl(requeued.queue, requeued.uniqueKey, requeued.id, requeued.deduplicationTtl ?? undefined);
|
|
217
|
+
}
|
|
180
218
|
shard.notify(requeued.queue);
|
|
181
219
|
return 1;
|
|
182
220
|
}
|
|
@@ -3,33 +3,62 @@ import { MAX_TIMELINE_ENTRIES } from '../domain/types/job';
|
|
|
3
3
|
import { retainDlqRetryState, scheduleNextRetry, setDlqRetryState } from '../domain/types/dlq';
|
|
4
4
|
import { shardIndex } from '../shared/hash';
|
|
5
5
|
function prepareRetry(job, now) {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
const timeline = [...job.timeline];
|
|
7
|
+
if (timeline.length < MAX_TIMELINE_ENTRIES)
|
|
8
|
+
timeline.push({ state: 'waiting', timestamp: now });
|
|
9
|
+
return {
|
|
10
|
+
...job,
|
|
11
|
+
attempts: 0,
|
|
12
|
+
lastHeartbeat: now,
|
|
13
|
+
runAt: now,
|
|
14
|
+
stallCount: 0,
|
|
15
|
+
startedAt: null,
|
|
16
|
+
timeline,
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function canRetry(queue, job, ctx) {
|
|
20
|
+
const idx = shardIndex(queue);
|
|
21
|
+
const shard = ctx.shards[idx];
|
|
22
|
+
const location = ctx.jobIndex.get(job.id);
|
|
23
|
+
if (location?.type !== 'dlq' || location.queueName !== queue)
|
|
24
|
+
return false;
|
|
25
|
+
const customOwner = job.customId ? ctx.customIdMap.get(job.customId) : undefined;
|
|
26
|
+
if (customOwner && customOwner !== job.id)
|
|
27
|
+
return false;
|
|
28
|
+
const keyOwner = job.uniqueKey ? shard.getUniqueKeyEntry(queue, job.uniqueKey) : null;
|
|
29
|
+
return keyOwner === null || keyOwner.jobId === job.id;
|
|
14
30
|
}
|
|
15
|
-
function
|
|
31
|
+
function publishRetry(queue, job, ctx) {
|
|
16
32
|
const idx = shardIndex(queue);
|
|
17
33
|
const shard = ctx.shards[idx];
|
|
18
|
-
prepareRetry(job, now);
|
|
19
34
|
shard.getQueue(queue).push(job);
|
|
20
|
-
shard.incrementQueued(job.id,
|
|
35
|
+
shard.incrementQueued(job.id, false, job.createdAt, queue, job.runAt);
|
|
21
36
|
ctx.jobIndex.set(job.id, { type: 'queue', shardIdx: idx, queueName: queue });
|
|
37
|
+
if (job.customId)
|
|
38
|
+
ctx.customIdMap.set(job.customId, job.id);
|
|
39
|
+
if (job.uniqueKey) {
|
|
40
|
+
shard.registerUniqueKeyWithTtl(queue, job.uniqueKey, job.id, job.deduplicationTtl ?? undefined);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function retryEntry(queue, entry, ctx, now, prepareState) {
|
|
44
|
+
if (!canRetry(queue, entry.job, ctx))
|
|
45
|
+
return null;
|
|
46
|
+
const job = prepareRetry(entry.job, now);
|
|
47
|
+
prepareState(job);
|
|
22
48
|
ctx.storage?.requeueDlqJob(job);
|
|
49
|
+
const removed = ctx.shards[shardIndex(queue)].removeFromDlq(queue, entry.job.id);
|
|
50
|
+
if (!removed)
|
|
51
|
+
throw new Error('DLQ entry disappeared after its retry committed');
|
|
52
|
+
publishRetry(queue, job, ctx);
|
|
53
|
+
return job;
|
|
23
54
|
}
|
|
24
55
|
/** Retry a single job from DLQ and reset the automatic retry generation. */
|
|
25
56
|
export function retryDlqJob(queue, jobId, ctx) {
|
|
26
57
|
const shard = ctx.shards[shardIndex(queue)];
|
|
27
|
-
const entry = shard.
|
|
58
|
+
const entry = shard.getDlqEntries(queue).find((candidate) => candidate.job.id === jobId);
|
|
28
59
|
if (!entry)
|
|
29
60
|
return null;
|
|
30
|
-
|
|
31
|
-
enqueueRetry(queue, entry.job, Date.now(), ctx);
|
|
32
|
-
return entry.job;
|
|
61
|
+
return retryEntry(queue, entry, ctx, Date.now(), (job) => setDlqRetryState(job, null));
|
|
33
62
|
}
|
|
34
63
|
/** Retry jobs from DLQ, optionally bounded to the oldest `limit` entries. */
|
|
35
64
|
export function retryDlqJobs(queue, ctx, jobId, limit) {
|
|
@@ -49,29 +78,21 @@ export function retryDlqJobs(queue, ctx, jobId, limit) {
|
|
|
49
78
|
}
|
|
50
79
|
return retried;
|
|
51
80
|
}
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
enqueueRetry(queue, entry.job, now, ctx);
|
|
59
|
-
}
|
|
60
|
-
return entries.length;
|
|
81
|
+
const ids = shard.getDlqEntries(queue).map((entry) => entry.job.id);
|
|
82
|
+
let retried = 0;
|
|
83
|
+
for (const id of ids)
|
|
84
|
+
if (retryDlqJob(queue, id, ctx))
|
|
85
|
+
retried++;
|
|
86
|
+
return retried;
|
|
61
87
|
}
|
|
62
88
|
/** Retry all DLQ entries selected by a metadata filter. */
|
|
63
89
|
export function retryDlqByFilter(queue, ctx, filter) {
|
|
64
90
|
const shard = ctx.shards[shardIndex(queue)];
|
|
65
91
|
const entries = [...shard.getDlqFiltered(queue, filter)];
|
|
66
|
-
const now = Date.now();
|
|
67
92
|
let retried = 0;
|
|
68
93
|
for (const entry of entries) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
continue;
|
|
72
|
-
setDlqRetryState(removed.job, null);
|
|
73
|
-
enqueueRetry(queue, removed.job, now, ctx);
|
|
74
|
-
retried++;
|
|
94
|
+
if (retryDlqJob(queue, entry.job.id, ctx))
|
|
95
|
+
retried++;
|
|
75
96
|
}
|
|
76
97
|
return retried;
|
|
77
98
|
}
|
|
@@ -85,13 +106,13 @@ export function processAutoRetry(queue, ctx) {
|
|
|
85
106
|
const entries = [...shard.getAutoRetryEntries(queue, now)];
|
|
86
107
|
let retried = 0;
|
|
87
108
|
for (const entry of entries) {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
109
|
+
const scheduled = { ...entry, attempts: [...entry.attempts] };
|
|
110
|
+
scheduleNextRetry(scheduled, config);
|
|
111
|
+
const job = retryEntry(queue, entry, ctx, now, (candidate) => {
|
|
112
|
+
retainDlqRetryState(candidate, scheduled);
|
|
113
|
+
});
|
|
114
|
+
if (job)
|
|
115
|
+
retried++;
|
|
95
116
|
}
|
|
96
117
|
return retried;
|
|
97
118
|
}
|
|
@@ -27,7 +27,7 @@ export declare class EventsManager {
|
|
|
27
27
|
* Wait for a specific job to complete - event-driven, no polling
|
|
28
28
|
* Returns true if job completed, false if timeout
|
|
29
29
|
*/
|
|
30
|
-
waitForJobCompletion(jobId: JobId, timeoutMs: number): Promise<boolean>;
|
|
30
|
+
waitForJobCompletion(jobId: JobId, timeoutMs: number, signal?: AbortSignal): Promise<boolean>;
|
|
31
31
|
/** Check if broadcast has any listeners - for batch optimizations */
|
|
32
32
|
needsBroadcast(): boolean;
|
|
33
33
|
/** Broadcast event to all subscribers - optimized to skip work when no listeners */
|