Skip to content
Get started
Get started
bunqueue v2.9.6
View Markdown
blog · release

bunqueue v2.9.6

Fixes 2 bugs. Unhandled rejections are reported again after a TCP client close.

bun add bunqueue@2.9.6
npm install bunqueue@2.9.6
TAG=2.9.6
docker run -p 6789:6789 -p 6790:6790 ghcr.io/egeominotti/bunqueue:$TAG
bun add bunqueue@latest
  • Unhandled rejections are reported again after a TCP client close. Applications that relied, knowingly or not, on bunqueue hiding their unhandled rejections now exit with code 1 after a client close(), as Bun and Node do by default. Handle the rejection, or register your own process.on('unhandledRejection', ...) listener if you want to keep running; bunqueue defers to it. Details under Client fixes below.
  • Flat connection options are rejected. Queue, Worker, FlowProducer, QueueEvents, Bunqueue, SandboxedWorker, QueueGroup.getQueue()/getWorker(), and the workflow Engine now throw when TCP-mode options carry top-level host, port, token, or tls. Those keys were never read, so the client silently connected to localhost:6789 without the intended token or TLS. Pass them as connection: { host, port, token, tls }. Embedded mode is unaffected. Regression: test/legacy-connection-options.test.ts.
  • Breaking minor release. The default bunqueue-client entry is the canonical bunqueue/client API, and the 0.1.x API stays unchanged at bunqueue-client/legacy. The unreleased version moved from 0.1.10 to 0.2.0 so ^0.1.9 ranges do not pick up the new API. In TCP mode, pause(), drain(), obliterate() and the other synchronous control calls do not wait for the broker, and synchronous reads return defaults; use the *Async variants. See the migration guide in sdk/typescript/README.md#migrating-from-01x.
  • Queued commands no longer fail with “Connection lost” when the broker starts after the client under Node, Deno, or Workers. The portable transport now reports a close only for connections that actually opened, as the Bun transport does. Regression: test/tcp-parity-late-broker.test.ts.
  • The package bundles as CommonJS again: the embedded engine loads lazily and synchronously under Bun instead of through a top-level await. Regression: test/client-parity-cjs-bundle.test.ts.
  • Published declarations no longer reference bun-types or leak Bun globals, and the package depends only on msgpackr. The build fails unless the declarations type-check for a strict NodeNext consumer with @types/node 20 or 22 and skipLibCheck: false.
  • The TLS, security, databases and examples guides and the README now pass bunqueue-client settings through connection.
  • Storage health recovers after a dropped projection-refresh retry. Lease renewals and batched completions that apply a job’s committed state, local claims, and authoritative queue refreshes now clear that job’s projection-refresh health error, and a failed getJob/getJobState read queues a background retry. Previously /health and /ready could report 503 until the job’s next event, or forever for a finished job. Regressions: test/repro-postgres-direct-projection-clears-health.test.ts and test/postgres-projection-health-recovery.test.ts.
  • Unhandled rejections are no longer swallowed after a TCP client close. TcpClient.close() installed a process-wide unhandledRejection listener that ignored every reason except ClientClosedError. Because any listener disables the Bun/Node default (print the error and exit 1), every unhandled rejection in the host application disappeared after the first close, with exit code 0. The filter still swallows synthetic ClientClosedError rejections, defers to application-owned listeners, and otherwise removes itself and re-raises the reason so the runtime’s configured mode applies. Global Symbol.for brands let duplicate bunqueue copies in one process share one filter, and a foreign error that is merely named ClientClosedError is no longer treated as bunqueue’s. Regression: test/repro-client-closed-filter-swallows-app-rejections.test.ts.
  • A TCP Worker with limiter.groupKey no longer FAILs a job that succeeded. A buffered job whose group value cannot be converted to a string (for example { toString: 'x' } from JSON or msgpack) made the dynamic ACK threshold throw after the ACK was queued. The successful job was then retried, a false failed event was emitted, and the stranded ACK was sent later with a stale token. The concurrency setter could throw for the same reason. Group-value extraction now never throws, keeps existing keys and falls back to a deterministic tag. If the dynamic ACK ceiling throws, the batcher uses the static batchSize, keeps the ACK, and reports an error event with context: 'ack-threshold'. Regression: test/repro-worker-group-value-poison-ack.test.ts.
  • Every published artifact of a run comes from one verified source commit. The 2.9.5 npm package and Docker images were built from main commits later than the v2.9.5 tag (105b8794): manual Docker rebuilds and npm publications checked out main. The version gate now outputs source_sha. It is the pushed commit for a new version, or the existing tag’s commit for a rebuild or npm publication, and the gate fails when that commit’s package.json disagrees. Binaries, images, the npm tarball, and the GitHub release (target_commitish) all use that commit. A rebuild fails on trees without the Docker variant inputs, so v2.9.5 itself cannot be rebuilt by this workflow. Images carry verified org.opencontainers.image.revision and version labels.
  • The TypeScript SDK release can authenticate. sdk-release.yml passed the token as NODE_AUTH_TOKEN, which Bun ignores. It now uses NPM_CONFIG_TOKEN, runs bun pm whoami and a dry run of the packed tarball, and then publishes that same tarball. The tag and registry gates fail closed. The --provenance flag and id-token: write permission were removed because Bun produces no provenance.
  • Every third-party GitHub Action is pinned to a full commit SHA, with a comment naming its release, in all workflows.
  • Redesign the homepage. The hero leads with adding a job in one language and processing it in another, shown by a simulated queue whose jobs move through waiting, delayed, active, retry and completed (static when reduced motion is requested). Capabilities follow the job lifecycle with matching state colors, storage reads as a path from memory to SQLite to PostgreSQL, and headings use condensed Bricolage Grotesque. The quickstart content is unchanged.
  • List public open-source projects that use bunqueue directly below the hero (context-labs/HALO, MagicCube/agentara, dosco/aithy and phuctm97/openkitten) with their GitHub star counts and a link to GitHub’s dependents graph.
  • The hero simulation has a Pause button, stops when reduced motion is turned on while the page is open, and is excluded from search snippets.
  • Search metadata: the homepage H1 names background jobs again and its meta description fits search results. Fifteen descriptions longer than 160 characters were shortened, 19 titles no longer repeat “bunqueue” in the suffix, URLs without a trailing slash redirect with 308 to the canonical page, current API reference pages gain a social image, and the changelog outline lists releases only.
  • Add a Web Dashboard guide for the open-source bunqueue dashboard: quick start, capabilities, a connection diagram, the actions that fail closed, deployment options, configuration variables, the security model for network access, and the experimental AI Copilot’s data handling. The homepage introduces the dashboard directly below the hero with a screenshot, the bunx bunqueue-dashboard command and links to the guide, the live demo and the repository. “Dashboard” is the first link in the header and mobile menu, and the sidebar lists the guide under Run in Production.
  • Audit the guide, API and architecture pages against the source and fix every error that could be verified. Examples that did not compile or run now do: Go job.Data() indexing without a type assertion, Go worker.Run() used as if it returned an error, untyped TypeScript job data, the Python minimal worker exiting before it processed a job, and Node.js DLQ calls that return nothing over TCP (getDlqAsync, purgeDlqAsync, setDlqConfigAsync). Retry delays in examples and the HTTP reference now follow the real formula (the first retry waits about twice the base backoff, with jitter, capped at one hour). The HTTP and TCP references gain the real webhook event names, named SSE events, /count and Cancel semantics, the 10,000-entry results cache, /health returning 503 when storage is degraded, bulk push keeping jobs accepted before a runtime admission error, and the missing PUSHF, SubscribeEvents and UnsubscribeEvents commands. Two security notes are corrected: a WebSocket connection must send its token in the upgrade request’s header, because the server refuses the upgrade without it (an Auth message after connecting never gets that far), and S3 backups rely on the bucket’s default encryption because bunqueue has no encryption option of its own. Type and architecture pages now match the exports, the 38-column jobs table and six model campaigns; BUNQUEUE_EMBEDDED is documented as a default rather than an override; the Compose example uses the published image and its /app/data volume; and the binary install downloads the published archive.

← bunqueue v2.9.5 · Release on GitHub · Commits since v2.9.5 · Full changelog · All posts