bunqueue-client 0.1.0 → 0.1.2
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.
- package/README.md +102 -66
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,36 +1,74 @@
|
|
|
1
|
-
# bunqueue-client
|
|
1
|
+
# bunqueue-client
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
the high-performance job queue server. Talks the native TCP protocol
|
|
5
|
-
(msgpack, pipelined, port 6789) — feature parity with the built-in Bun client,
|
|
6
|
-
but runs on **any** modern JS/TS runtime.
|
|
3
|
+
Official TypeScript client for [bunqueue](https://github.com/egeominotti/bunqueue), the high performance job queue server. The client implements the native TCP protocol (msgpack, pipelined) and provides full feature parity with the built in Bun client, while running on every modern JavaScript runtime.
|
|
7
4
|
|
|
8
|
-
The bunqueue
|
|
9
|
-
Node, Bun, or Deno service produce and consume jobs on it: *one queue, any
|
|
10
|
-
language, any runtime*.
|
|
5
|
+
The bunqueue server runs on Bun, distributed as a binary or a Docker image. This client allows any Node.js, Bun, Deno, or Cloudflare Workers service to produce and consume jobs against it: one queue, any language, any runtime.
|
|
11
6
|
|
|
12
|
-
##
|
|
7
|
+
## Compatibility
|
|
13
8
|
|
|
14
9
|
| Runtime | Status | Notes |
|
|
15
10
|
|---|---|---|
|
|
16
|
-
| Node.js
|
|
17
|
-
| Bun |
|
|
18
|
-
| Deno
|
|
19
|
-
| tsx
|
|
20
|
-
| Cloudflare Workers |
|
|
21
|
-
| Browser |
|
|
11
|
+
| Node.js 20 or later | Supported, 58/58 e2e and 8/8 integration tests | ESM. TypeScript files run directly on Node 22 or later via `--experimental-strip-types` |
|
|
12
|
+
| Bun | Supported, 58/58 e2e and 8/8 integration tests | No additional configuration required |
|
|
13
|
+
| Deno 2 or later | Supported, 58/58 e2e and 8/8 integration tests | Uses `node:` builtins and the npm `msgpackr` package |
|
|
14
|
+
| tsx, ts-node, vitest, jest | Supported | These environments execute on Node.js |
|
|
15
|
+
| Cloudflare Workers | Supported, 11/11 e2e tests inside workerd | Requires the `nodejs_compat` compatibility flag. The runtime is request scoped, so long lived worker loops are not available: consume in batches from Cron Triggers or Durable Object alarms, a pattern covered by the test suite. TLS connections require a publicly trusted certificate |
|
|
16
|
+
| Browser | Not supported | Raw TCP sockets are unavailable. Use the server HTTP API instead |
|
|
22
17
|
|
|
23
|
-
|
|
24
|
-
(`net`, `tls`, `events`, `crypto`, `os`) — no `Bun.*` globals, no
|
|
25
|
-
`bun:`/`deno:` imports. Single runtime dependency: `msgpackr`.
|
|
18
|
+
Portability is guaranteed by design: the client relies exclusively on `node:*` builtins (`net`, `tls`, `events`, `crypto`, `os`), uses no `Bun.*` globals and no runtime specific imports, and carries a single runtime dependency, `msgpackr`.
|
|
26
19
|
|
|
27
|
-
##
|
|
20
|
+
## Installation
|
|
28
21
|
|
|
29
22
|
```bash
|
|
30
|
-
npm install bunqueue-client
|
|
23
|
+
npm install bunqueue-client
|
|
24
|
+
# or: bun add bunqueue-client / pnpm add bunqueue-client / deno add npm:bunqueue-client
|
|
31
25
|
```
|
|
32
26
|
|
|
33
|
-
##
|
|
27
|
+
## Quick start
|
|
28
|
+
|
|
29
|
+
Sixty seconds from zero to a working queue. Step 1, start the server (requires [Bun](https://bun.sh), or use the Docker image):
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bunx bunqueue start
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Step 2, create `app.ts`: add a job and process it, in the same file for the sake of the demo:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { Queue, Worker } from 'bunqueue-client';
|
|
39
|
+
|
|
40
|
+
const worker = new Worker('hello', async (job) => {
|
|
41
|
+
console.log('processing', job.data);
|
|
42
|
+
return { greeted: job.data.name };
|
|
43
|
+
});
|
|
44
|
+
worker.on('completed', (job, result) => {
|
|
45
|
+
console.log('completed', job.id, result);
|
|
46
|
+
worker.close();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
const queue = new Queue('hello');
|
|
50
|
+
await queue.add('greet', { name: 'world' });
|
|
51
|
+
queue.close();
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Step 3, run it with the runtime you already use:
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
node --experimental-strip-types app.ts # Node 22 or later
|
|
58
|
+
bun app.ts # Bun
|
|
59
|
+
deno run -A app.ts # Deno 2 or later
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Expected output:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
processing { name: 'world' }
|
|
66
|
+
completed 019f40a5-... { greeted: 'world' }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That is the whole model: the server owns state, retries, and scheduling, your code only adds and processes. In production the producer and the worker are separate services, often in different languages: the [Python client](https://github.com/egeominotti/bunqueue/tree/main/sdk/python) speaks the same protocol against the same queue. Defaults are `host: 'localhost'`, `port: 6789`, so constructors need no options on a local setup.
|
|
70
|
+
|
|
71
|
+
## Producing jobs
|
|
34
72
|
|
|
35
73
|
```typescript
|
|
36
74
|
import { Queue } from 'bunqueue-client';
|
|
@@ -47,7 +85,7 @@ const counts = await queue.getJobCounts();
|
|
|
47
85
|
queue.close();
|
|
48
86
|
```
|
|
49
87
|
|
|
50
|
-
##
|
|
88
|
+
## Processing jobs
|
|
51
89
|
|
|
52
90
|
```typescript
|
|
53
91
|
import { Worker, UnrecoverableError } from 'bunqueue-client';
|
|
@@ -56,7 +94,7 @@ const worker = new Worker(
|
|
|
56
94
|
'emails',
|
|
57
95
|
async (job) => {
|
|
58
96
|
await job.updateProgress(50);
|
|
59
|
-
if (job.data.invalid) throw new UnrecoverableError('bad payload'); // no retries
|
|
97
|
+
if (job.data.invalid) throw new UnrecoverableError('bad payload'); // no retries, straight to the DLQ
|
|
60
98
|
return { sent: true };
|
|
61
99
|
},
|
|
62
100
|
{ host: 'localhost', port: 6789, concurrency: 10 }
|
|
@@ -65,11 +103,10 @@ const worker = new Worker(
|
|
|
65
103
|
worker.on('completed', (job, result) => console.log(job.id, result));
|
|
66
104
|
worker.on('failed', (job, err) => console.error(job.id, err.message));
|
|
67
105
|
|
|
68
|
-
// later: await worker.close(); // graceful
|
|
106
|
+
// later: await worker.close(); // graceful shutdown, waits for in flight jobs
|
|
69
107
|
```
|
|
70
108
|
|
|
71
|
-
Retry, backoff,
|
|
72
|
-
**server-side** — the worker only pulls, heartbeats and acks.
|
|
109
|
+
Retry, backoff, dead letter queue, stall detection, priorities, and rate limiting all execute server side. The worker only pulls, heartbeats, and acknowledges, which keeps the client thin and the behavior consistent across languages.
|
|
73
110
|
|
|
74
111
|
## Flows
|
|
75
112
|
|
|
@@ -78,14 +115,14 @@ import { FlowProducer } from 'bunqueue-client';
|
|
|
78
115
|
|
|
79
116
|
const flow = new FlowProducer({ host: 'localhost', port: 6789 });
|
|
80
117
|
|
|
81
|
-
// sequential chain: step1
|
|
118
|
+
// sequential chain: step1, then step2, then step3
|
|
82
119
|
await flow.addChain([
|
|
83
120
|
{ name: 'step1', queueName: 'pipeline' },
|
|
84
121
|
{ name: 'step2', queueName: 'pipeline' },
|
|
85
122
|
{ name: 'step3', queueName: 'pipeline' },
|
|
86
123
|
]);
|
|
87
124
|
|
|
88
|
-
// fan
|
|
125
|
+
// fan in: parallel jobs converge into a final job that reads their results
|
|
89
126
|
const { finalId } = await flow.addBulkThen(
|
|
90
127
|
[
|
|
91
128
|
{ name: 'part1', queueName: 'pipeline' },
|
|
@@ -95,7 +132,7 @@ const { finalId } = await flow.addBulkThen(
|
|
|
95
132
|
);
|
|
96
133
|
// inside the 'merge' processor: await job.getChildrenValues()
|
|
97
134
|
|
|
98
|
-
// parent
|
|
135
|
+
// parent and child tree: children always run before the parent
|
|
99
136
|
const node = await flow.add({
|
|
100
137
|
name: 'assemble', queueName: 'orders',
|
|
101
138
|
children: [
|
|
@@ -105,7 +142,7 @@ const node = await flow.add({
|
|
|
105
142
|
});
|
|
106
143
|
```
|
|
107
144
|
|
|
108
|
-
##
|
|
145
|
+
## Scheduling
|
|
109
146
|
|
|
110
147
|
```typescript
|
|
111
148
|
await queue.addCron('daily-report', '0 9 * * *', { type: 'report' });
|
|
@@ -113,53 +150,52 @@ await queue.every('health-ping', 30_000, { type: 'ping' });
|
|
|
113
150
|
await queue.removeJobScheduler('daily-report');
|
|
114
151
|
```
|
|
115
152
|
|
|
116
|
-
##
|
|
153
|
+
## Security
|
|
117
154
|
|
|
118
155
|
```typescript
|
|
119
156
|
const queue = new Queue('emails', {
|
|
120
157
|
host: 'queue.example.com',
|
|
121
158
|
port: 6789,
|
|
122
159
|
token: process.env.BUNQUEUE_TOKEN,
|
|
123
|
-
tls: { caFile: './ca.pem' }, // or `true` for system
|
|
160
|
+
tls: { caFile: './ca.pem' }, // or `true` for system certificate authorities
|
|
124
161
|
});
|
|
125
162
|
```
|
|
126
163
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
## Development
|
|
164
|
+
Authentication uses server side tokens (`AUTH_TOKENS`). Transport security uses native TLS, with support for system certificate authorities, a custom CA bundle, or disabled verification for development environments.
|
|
165
|
+
|
|
166
|
+
## API surface
|
|
167
|
+
|
|
168
|
+
| Area | Capabilities |
|
|
169
|
+
|---|---|
|
|
170
|
+
| Queue | `add`, `addBulk`, full `JobOptions`: priority, delay, attempts, backoff, ttl, timeout, jobId, deduplication, dependsOn, tags, groupId, lifo, removeOnComplete, removeOnFail, durable, repeat, debounce |
|
|
171
|
+
| Query | `getJob`, `getJobByCustomId`, `getJobs` with per state helpers, state, result, progress, `waitForJob`, counts, counts per priority, children values, job logs |
|
|
172
|
+
| Control | pause, resume, drain, obliterate, clean, remove, discard, promote, `retryJob`, `retryJobs`, move to wait or delayed, change priority or delay, update data, extend lock |
|
|
173
|
+
| Dead letter queue | `getDlq`, `retryDlq`, `purgeDlq`, DLQ configuration |
|
|
174
|
+
| Administration | rate limiting, global concurrency, stall configuration, webhooks, stats, metrics, `listQueues`, `getWorkers` |
|
|
175
|
+
| Worker events | `ready`, `active`, `completed`, `failed`, `progress`, `drained`, `error`, `closed`, with automatic lock heartbeats so that jobs longer than the lock TTL survive |
|
|
176
|
+
|
|
177
|
+
The following features require the in process Bun runtime and are intentionally out of scope for this client: embedded mode, sandboxed workers, and `QueueEvents`. Use webhooks or the HTTP SSE and WebSocket endpoints for event streaming.
|
|
178
|
+
|
|
179
|
+
Note on numeric payloads: JavaScript numbers are IEEE 754 doubles, exact up to 2^53. Pass larger 64 bit identifiers, for example snowflake IDs, as strings to avoid silent precision loss. Never place `BigInt` values in job data.
|
|
180
|
+
|
|
181
|
+
## Quality assurance
|
|
182
|
+
|
|
183
|
+
Every release is validated against a real bunqueue server, spawned fresh for each run, across every supported runtime:
|
|
149
184
|
|
|
150
185
|
```bash
|
|
151
186
|
bun install
|
|
152
|
-
bun run build # tsc
|
|
153
|
-
bun run check #
|
|
154
|
-
|
|
155
|
-
#
|
|
156
|
-
bun tests/
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
bun run test:workers # full suite INSIDE workerd (Cloudflare Workers)
|
|
187
|
+
bun run build # tsc, emits dist/
|
|
188
|
+
bun run check # Biome lint and format verification
|
|
189
|
+
|
|
190
|
+
bun tests/integration.ts # smoke suite
|
|
191
|
+
bun tests/e2e.ts # full surface, edge cases, realistic load
|
|
192
|
+
node --experimental-strip-types tests/e2e.ts # identical suite on Node 22 or later
|
|
193
|
+
deno run -A tests/e2e.ts # identical suite on Deno 2 or later
|
|
194
|
+
bun run test:workers # full suite inside workerd, the Cloudflare Workers runtime
|
|
161
195
|
```
|
|
162
196
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
197
|
+
The e2e suite includes payload limits, unicode integrity, pipelining under concurrency, server crash and restart with automatic reconnection, and a realistic multi queue production scenario with zero loss accounting. Engineering standards: Biome, a maximum of 250 lines per file, and relative imports with explicit `.js` extensions for NodeNext resolution. See `CLAUDE.md` for the full development guide and wire protocol notes.
|
|
198
|
+
|
|
199
|
+
## License
|
|
200
|
+
|
|
201
|
+
MIT. See the [LICENSE](./LICENSE) file. Documentation: [bunqueue.dev/guide/sdks](https://bunqueue.dev/guide/sdks/). Issues and feature requests: [GitHub issues](https://github.com/egeominotti/bunqueue/issues).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bunqueue-client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Cross-runtime TypeScript client for the bunqueue job queue server — Node.js, Bun, Deno and Cloudflare Workers",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"lint": "biome lint src tests",
|
|
30
30
|
"format": "biome format --write src tests",
|
|
31
31
|
"check": "biome check src tests",
|
|
32
|
-
"test:workers": "cd tests/workers && node run.mjs"
|
|
32
|
+
"test:workers": "bun pm pack --destination tests/workers && cd tests/workers && mv bunqueue-client-*.tgz bunqueue-client.tgz && bun install && node run.mjs"
|
|
33
33
|
},
|
|
34
34
|
"keywords": [
|
|
35
35
|
"queue",
|