bunqueue v2.8.24
Ships 3 performance improvements. Deterministic micro-benchmark (addData, 111-byte frames coalesced into one read): F=1000 2.78ms → 0.043ms (~65×), F=5000 61.1ms → 0.21ms (~291×).
To install bunqueue v2.8.24
Section titled “To install bunqueue v2.8.24”bun add bunqueue@2.8.24npm install bunqueue@2.8.24To upgrade bunqueue
Section titled “To upgrade bunqueue”bun add bunqueue@latestPerformance: fewer copies and an O(Q²) background scan removed
Section titled “Performance: fewer copies and an O(Q²) background scan removed”- Dropped a redundant
new Uint8Array(data)copy in both TCP data handlers (src/infrastructure/server/tcp.ts,src/client/tcp/connection.ts).addDataalready copies the incoming bytes into its own buffer synchronously and never retains the caller’s buffer, so the defensive wrapper was one full copy per read with no purpose. cleanEmptyQueuesO(Q²) → O(Q) (src/application/cleanupTasks.ts). The 10s background sweep called theshard.dlqgetter, which rebuilds aMapof every queue’s DLQ entries on each access, once per queue, making the per-shard sweep quadratic in the queue count. Replaced with the O(1)shard.getDlqCount(queue)counter lookup. Read-side only; no behavior change.
Performance
Section titled “Performance”FrameParser.addData (src/infrastructure/server/protocol.ts), used by both the TCP server (incoming commands) and the TCP client (incoming responses), resliced the entire remaining buffer after every decoded frame: this.buffer = this.buffer.slice(4 + len). When many frames arrive coalesced in a single TCP read, exactly what deep pipelining and OS segment coalescing produce for PUSHB/ACKB bursts, that is O(tail) per frame, i.e. O(F²) in the number of frames per read. Replaced with a read-offset cursor that advances in O(1) per frame and compacts the unconsumed tail once, making the pass O(total bytes).
- Deterministic micro-benchmark (
addData, 111-byte frames coalesced into one read): F=1000 2.78ms → 0.043ms (~65×), F=5000 61.1ms → 0.21ms (~291×). Linear scaling restored (5× frames → ~5× time). - End-to-end (M1 Max, Bun 1.3.14): TCP push throughput +20–36% at 1K–5K-job scales where frame coalescing is heaviest, neutral at larger scales;
tcp-benchround-trip latency p50 48µs → 43µs (−10%). Embedded mode is unaffected (it does not use the wire framing). - Behavior is byte-for-byte identical: frame bodies are still returned as copies, partial-frame buffering, the 64MB
FrameSizeErrorguard, and the slowlorishasPartialFrame/bufferedBytesgetters are preserved. New E2E suitescripts/tcp/test-frameparser-pipelining-e2e.tsvalidates 2000-way pipelined coalescing, 256KB multi-segment frames, 5000-job exactly-once processing, and boundary-size payload integrity.
Docs: benchmarks page re-measured and corrected
Section titled “Docs: benchmarks page re-measured and corrected”Re-ran every published benchmark on an Apple M1 Max (Bun 1.3.14), reporting the median of 3 runs per cell, and updated guide/benchmarks. Embedded numbers reproduce (and are higher than before: bulk push peaks ~630K ops/sec). The TCP “Process” figures were corrected: the old 20–34K ops/sec single-worker numbers predate the lease-bounding over-pull fix and no longer reproduce, a single worker at concurrency:10 is bounded by per-job pull round-trip latency (~182 ops/sec), scaling to ~4,900 ops/sec at concurrency:50. The methodology section now also documents that the TCP “Push” column issues 100 concurrent adds per batch (not sequential) and notes the BUNQUEUE_EMBEDDED env caveat when running bench/comprehensive.ts.
Thanks to 1 contributor!
Section titled “Thanks to 1 contributor!”← bunqueue v2.8.23 · Release on GitHub · Commits since v2.8.23 · Full changelog · All posts