bunqueue v2.9.6
blog · release
bunqueue v2.9.6
Fixes 2 bugs. Unhandled rejections are reported again after a TCP client close.
To install bunqueue v2.9.6
Section titled “To install bunqueue v2.9.6”bun add bunqueue@2.9.6npm install bunqueue@2.9.6TAG=2.9.6docker run -p 6789:6789 -p 6790:6790 ghcr.io/egeominotti/bunqueue:$TAGTo upgrade bunqueue
Section titled “To upgrade bunqueue”bun add bunqueue@latestBehavior changes
Section titled “Behavior changes”- 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 ownprocess.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 workflowEnginenow throw when TCP-mode options carry top-levelhost,port,token, ortls. Those keys were never read, so the client silently connected tolocalhost:6789without the intended token or TLS. Pass them asconnection: { host, port, token, tls }. Embedded mode is unaffected. Regression:test/legacy-connection-options.test.ts.
TypeScript SDK (bunqueue-client 0.2.0)
Section titled “TypeScript SDK (bunqueue-client 0.2.0)”- Breaking minor release. The default
bunqueue-cliententry is the canonicalbunqueue/clientAPI, and the 0.1.x API stays unchanged atbunqueue-client/legacy. The unreleased version moved from 0.1.10 to 0.2.0 so^0.1.9ranges 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*Asyncvariants. See the migration guide insdk/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-typesor leak Bun globals, and the package depends only onmsgpackr. The build fails unless the declarations type-check for a strict NodeNext consumer with@types/node20 or 22 andskipLibCheck: false. - The TLS, security, databases and examples guides and the README now pass
bunqueue-client settings through
connection.
PostgreSQL
Section titled “PostgreSQL”- 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-refreshhealth error, and a failedgetJob/getJobStateread queues a background retry. Previously/healthand/readycould report 503 until the job’s next event, or forever for a finished job. Regressions:test/repro-postgres-direct-projection-clears-health.test.tsandtest/postgres-projection-health-recovery.test.ts.
Client fixes
Section titled “Client fixes”- Unhandled rejections are no longer swallowed after a TCP client close.
TcpClient.close()installed a process-wideunhandledRejectionlistener that ignored every reason exceptClientClosedError. 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 syntheticClientClosedErrorrejections, defers to application-owned listeners, and otherwise removes itself and re-raises the reason so the runtime’s configured mode applies. GlobalSymbol.forbrands let duplicate bunqueue copies in one process share one filter, and a foreign error that is merely namedClientClosedErroris no longer treated as bunqueue’s. Regression:test/repro-client-closed-filter-swallows-app-rejections.test.ts. - A TCP Worker with
limiter.groupKeyno 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 falsefailedevent was emitted, and the stranded ACK was sent later with a stale token. Theconcurrencysetter 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 staticbatchSize, keeps the ACK, and reports anerrorevent withcontext: '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.5tag (105b8794): manual Docker rebuilds and npm publications checked out main. The version gate now outputssource_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’spackage.jsondisagrees. 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 verifiedorg.opencontainers.image.revisionandversionlabels. - The TypeScript SDK release can authenticate.
sdk-release.ymlpassed the token asNODE_AUTH_TOKEN, which Bun ignores. It now usesNPM_CONFIG_TOKEN, runsbun pm whoamiand a dry run of the packed tarball, and then publishes that same tarball. The tag and registry gates fail closed. The--provenanceflag andid-token: writepermission 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.
Documentation
Section titled “Documentation”- 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-dashboardcommand 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, Goworker.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 basebackoff, with jitter, capped at one hour). The HTTP and TCP references gain the real webhook event names, named SSE events,/countand Cancel semantics, the 10,000-entry results cache,/healthreturning 503 when storage is degraded, bulk push keeping jobs accepted before a runtime admission error, and the missingPUSHF,SubscribeEventsandUnsubscribeEventscommands. 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 (anAuthmessage 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-columnjobstable and six model campaigns;BUNQUEUE_EMBEDDEDis documented as a default rather than an override; the Compose example uses the published image and its/app/datavolume; and the binary install downloads the published archive.
Thanks to 1 contributor!
Section titled “Thanks to 1 contributor!”← bunqueue v2.9.5 · Release on GitHub · Commits since v2.9.5 · Full changelog · All posts