bunqueue 2.8.17 → 2.8.18
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.
|
@@ -48,6 +48,7 @@ export declare class Worker<T = unknown, R = unknown> extends EventEmitter {
|
|
|
48
48
|
private pendingJobs;
|
|
49
49
|
private pendingJobsHead;
|
|
50
50
|
private processingScheduled;
|
|
51
|
+
private pendingPull;
|
|
51
52
|
private lastDrainedEmit;
|
|
52
53
|
private stalledUnsubscribe;
|
|
53
54
|
on(event: 'ready' | 'drained' | 'closed', listener: () => void): this;
|
|
@@ -102,6 +102,9 @@ export class Worker extends EventEmitter {
|
|
|
102
102
|
pendingJobs = [];
|
|
103
103
|
pendingJobsHead = 0;
|
|
104
104
|
processingScheduled = false; // Prevent multiple setImmediate calls
|
|
105
|
+
// Slots reserved by in-flight doPullBatch() calls (Issue #98). Subtracted from
|
|
106
|
+
// free slots so overlapping pulls see each other and do not over-lease.
|
|
107
|
+
pendingPull = 0;
|
|
105
108
|
// Drained event tracking
|
|
106
109
|
lastDrainedEmit = 0;
|
|
107
110
|
// Stalled event subscription (BullMQ v5 compatible)
|
|
@@ -703,14 +706,46 @@ export class Worker extends EventEmitter {
|
|
|
703
706
|
return null;
|
|
704
707
|
}
|
|
705
708
|
async doPullBatch() {
|
|
706
|
-
|
|
709
|
+
// Issue #98: cap the LEASED count (running + buffered + in-flight pulls) at
|
|
710
|
+
// `concurrency`, not just the running count. The old `concurrency - activeJobs`
|
|
711
|
+
// was read once and the pull leases jobs on the broker across an await, so:
|
|
712
|
+
// 1. several concurrent finally->poll->tryProcess runs each read the same
|
|
713
|
+
// stale count and each pull a full batch, and
|
|
714
|
+
// 2. a job just pulled by one run sits in `pendingJobs` (leased, counted by
|
|
715
|
+
// the heartbeat) but not yet in `activeJobs`, so an overlapping pull does
|
|
716
|
+
// not see it.
|
|
717
|
+
// Both leak: with concurrency=3 the worker ends up holding 5-6 jobs leased.
|
|
718
|
+
// `pulledJobIds.size` is the true leased count (active + buffered; a job is
|
|
719
|
+
// removed only on completion), and `pendingPull` reserves slots for pulls
|
|
720
|
+
// still in flight whose jobs are not yet registered.
|
|
721
|
+
//
|
|
722
|
+
// Exception — group pull-ahead: when a group limiter is set AND the buffer is
|
|
723
|
+
// non-empty here (this branch is reached only after getNextEligibleJob() found
|
|
724
|
+
// nothing runnable, so those buffered jobs are group-blocked), the worker must
|
|
725
|
+
// pull ahead to discover jobs from other, runnable groups — otherwise it would
|
|
726
|
+
// wedge on a buffer full of one blocked group. In that case the blocked
|
|
727
|
+
// buffered jobs are not counted (only the running ones are). This preserves the
|
|
728
|
+
// existing group behavior; the reported over-pull (no group limiter) always
|
|
729
|
+
// uses the strict leased cap.
|
|
730
|
+
const groupBlockedBuffer = this.groupLimiter !== null && this.pendingJobsHead < this.pendingJobs.length;
|
|
731
|
+
const leased = groupBlockedBuffer ? this.activeJobs : this.pulledJobIds.size;
|
|
732
|
+
const slots = this.opts.concurrency - leased - this.pendingPull;
|
|
707
733
|
const batchSize = Math.min(this.opts.batchSize, slots, 1000);
|
|
708
734
|
if (batchSize <= 0)
|
|
709
735
|
return [];
|
|
710
736
|
const config = this.getPullConfig();
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
737
|
+
this.pendingPull += batchSize;
|
|
738
|
+
try {
|
|
739
|
+
return this.embedded
|
|
740
|
+
? await pullEmbedded(config, batchSize)
|
|
741
|
+
: await pullTcp(config, this.tcp, batchSize, this._closing);
|
|
742
|
+
}
|
|
743
|
+
finally {
|
|
744
|
+
// Release the reservation. The pulled jobs are now registered/buffered (or
|
|
745
|
+
// the pull failed); either way the reservation has served its purpose for
|
|
746
|
+
// the duration of the in-flight pull.
|
|
747
|
+
this.pendingPull -= batchSize;
|
|
748
|
+
}
|
|
714
749
|
}
|
|
715
750
|
startJob(job, token) {
|
|
716
751
|
const jobIdStr = String(job.id);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunqueue",
|
|
3
|
-
"version": "2.8.
|
|
3
|
+
"version": "2.8.18",
|
|
4
4
|
"description": "High-performance job queue for Bun & AI agents. SQLite persistence, cron scheduling, priorities, retries, DLQ, webhooks, native MCP server. Zero external dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/main.js",
|