# bunqueue v2.8.18

Fixes 1 bug. A Worker leased more jobs than concurrency, inflating the broker's active count and starving other workers (src/client/worker/worker.ts): the #96 fix capped _execution_ (activeJobs) at concurrency, but doPullBatch() computed…

Canonical: https://bunqueue.dev/blog/bunqueue-v2-8-18/

---

<!-- Generated from changelog.md by docs/scripts/generate-release-posts.ts. Edit the changelog and regenerate. -->

Fixes 1 bug. A Worker leased more jobs than concurrency, inflating the broker's active count and starving other workers (src/client/worker/worker.ts): the #96 fix capped _execution_ (activeJobs) at concurrency, but doPullBatch() computed…

![](https://github.com/egeominotti.png?size=64) [egeominotti](https://github.com/egeominotti)

#### To install bunqueue v2.8.18

```bash title="bun"
bun add bunqueue@2.8.18
```

```bash title="npm"
npm install bunqueue@2.8.18
```

#### To upgrade bunqueue

```bash
bun add bunqueue@latest
```

## Bugfixes

- **A Worker leased more jobs than `concurrency`, inflating the broker's `active` count and starving other workers** (`src/client/worker/worker.ts`): the #96 fix capped _execution_ (`activeJobs`) at `concurrency`, but `doPullBatch()` computed free slots as `concurrency - activeJobs` and then awaited the pull with no reservation. Two leaks compounded: (1) several concurrent `finally → poll → tryProcess` runs each read the same stale `activeJobs` and each pulled a full batch; (2) a job just pulled by one run sat in the local `pendingJobs` buffer, leased and kept alive by the heartbeat (which renews locks for _all_ `pulledJobIds`, not just running ones), but not yet in `activeJobs`, so an overlapping pull never saw it. With `concurrency: 3` the worker held 5-6 jobs leased (3 running + buffered). `doPullBatch()` now caps the **leased** count (running + buffered + in-flight pulls): a new `pendingPull` counter reserves slots before the await (released in `finally`), and free slots are computed from `pulledJobIds.size` (the true leased set) instead of `activeJobs`. Group pull-ahead is preserved: when a group limiter is set and the buffer holds only group-blocked jobs, the worker still pulls ahead to find runnable jobs from other groups (verified by a liveness regression guard, no deadlock/starvation). Execution concurrency was already correct (no data loss); this fixes lease hoarding, the inflated `active` count, and head-of-line fairness across workers.

## Thanks to 1 contributor!

- [@egeominotti](https://github.com/egeominotti)

---

[← bunqueue v2.8.17](https://bunqueue.dev/blog/bunqueue-v2-8-17/) · [Release on GitHub](https://github.com/egeominotti/bunqueue/releases/tag/v2.8.18) · [Commits since v2.8.17](https://github.com/egeominotti/bunqueue/compare/v2.8.17...v2.8.18) · [Full changelog](https://bunqueue.dev/changelog/) · [All posts](https://bunqueue.dev/blog/)
