bunqueue 1.9.4 β†’ 1.9.5

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.
Files changed (2) hide show
  1. package/README.md +26 -819
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -6,860 +6,67 @@
6
6
  <a href="https://github.com/egeominotti/bunqueue/actions"><img src="https://github.com/egeominotti/bunqueue/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
7
7
  <a href="https://github.com/egeominotti/bunqueue/releases"><img src="https://img.shields.io/github/v/release/egeominotti/bunqueue" alt="Release"></a>
8
8
  <a href="https://github.com/egeominotti/bunqueue/blob/main/LICENSE"><img src="https://img.shields.io/github/license/egeominotti/bunqueue" alt="License"></a>
9
+ <a href="https://www.npmjs.com/package/bunqueue"><img src="https://img.shields.io/npm/v/bunqueue" alt="npm"></a>
9
10
  </p>
10
11
 
11
12
  <p align="center">
12
- <a href="https://egeominotti.github.io/bunqueue/"><strong>πŸ“š Documentation</strong></a> β€’
13
- <a href="#features">Features</a> β€’
14
- <a href="#quick-start">Quick Start</a> β€’
15
- <a href="#embedded-mode">Embedded</a> β€’
16
- <a href="#server-mode">Server</a> β€’
17
- <a href="#docker">Docker</a>
13
+ <strong>High-performance job queue for Bun. Zero external dependencies.</strong>
18
14
  </p>
19
15
 
20
16
  <p align="center">
21
- <a href="https://www.npmjs.com/package/bunqueue"><img src="https://img.shields.io/npm/v/bunqueue?label=bunqueue" alt="bunqueue npm"></a>
22
- <a href="https://www.npmjs.com/package/bunqueue"><img src="https://img.shields.io/npm/dm/bunqueue" alt="npm downloads"></a>
17
+ <a href="https://egeominotti.github.io/bunqueue/"><strong>Documentation</strong></a>
23
18
  </p>
24
19
 
25
20
  ---
26
21
 
27
22
  ## Why bunqueue?
28
23
 
29
- > ⚠️ **Bun only** β€” bunqueue requires [Bun](https://bun.sh) runtime. Node.js is not supported.
30
-
31
- **Every other job queue requires external infrastructure.** bunqueue doesn't.
32
-
33
24
  | Library | Requires |
34
25
  |---------|----------|
35
- | BullMQ | ❌ Redis |
36
- | Agenda | ❌ MongoDB |
37
- | Bee-Queue | ❌ Redis |
38
- | pg-boss | ❌ PostgreSQL |
39
- | Celery | ❌ Redis/RabbitMQ |
40
- | **bunqueue** | βœ… **Nothing. Zero. Nada.** |
26
+ | BullMQ | Redis |
27
+ | Agenda | MongoDB |
28
+ | pg-boss | PostgreSQL |
29
+ | **bunqueue** | **Nothing** |
41
30
 
42
- bunqueue is the **only** job queue with:
43
- - **BullMQ-compatible API** β€” Same `Queue`, `Worker`, `QueueEvents` you know
44
- - **Zero external dependencies** β€” No Redis, no MongoDB, no nothing
45
- - **Persistent storage** β€” SQLite survives restarts, no data loss
46
- - **100K+ jobs/sec** β€” Faster than Redis-based queues
47
- - **Single file deployment** β€” Just your app, that's it
31
+ - **BullMQ-compatible API** β€” Same `Queue`, `Worker`, `QueueEvents`
32
+ - **Zero dependencies** β€” No Redis, no MongoDB
33
+ - **SQLite persistence** β€” Survives restarts
34
+ - **100K+ jobs/sec** β€” Built on Bun
48
35
 
49
- ```bash
50
- # Others: Install Redis, configure connection, manage infrastructure...
51
- # bunqueue:
52
- bun add bunqueue
53
- ```
54
-
55
- ```typescript
56
- import { Queue, Worker } from 'bunqueue/client';
57
- // That's it. You're done. Start queuing.
58
- ```
59
-
60
- ---
61
-
62
- ## Quick Install
36
+ ## Install
63
37
 
64
38
  ```bash
65
- # Requires Bun runtime (https://bun.sh)
66
39
  bun add bunqueue
67
40
  ```
68
41
 
69
- bunqueue works in **two modes**:
70
-
71
- | Mode | Description | Use Case |
72
- |------|-------------|----------|
73
- | **Embedded** | In-process, no server needed | Monolith, scripts, serverless |
74
- | **Server** | Standalone TCP/HTTP server | Microservices, multi-process |
75
-
76
- ---
77
-
78
- ## Quick Start
79
-
80
- ### Embedded Mode (Recommended)
42
+ > Requires [Bun](https://bun.sh) runtime. Node.js is not supported.
81
43
 
82
- No server required. BullMQ-compatible API.
83
-
84
- > **Important:** Both `Queue` and `Worker` must have `embedded: true` to use embedded mode.
44
+ ## Quick Example
85
45
 
86
46
  ```typescript
87
47
  import { Queue, Worker } from 'bunqueue/client';
88
48
 
89
- // Create queue - MUST have embedded: true
90
49
  const queue = new Queue('emails', { embedded: true });
91
50
 
92
- // Create worker - MUST have embedded: true
93
51
  const worker = new Worker('emails', async (job) => {
94
- console.log('Sending email to:', job.data.to);
95
- await job.updateProgress(50);
96
- return { sent: true };
97
- }, { embedded: true, concurrency: 5 });
98
-
99
- // Handle events
100
- worker.on('completed', (job, result) => {
101
- console.log(`Job ${job.id} completed:`, result);
102
- });
103
-
104
- worker.on('failed', (job, err) => {
105
- console.error(`Job ${job.id} failed:`, err.message);
106
- });
107
-
108
- // Add jobs
109
- await queue.add('send-welcome', { to: 'user@example.com' });
110
- ```
111
-
112
- **With persistence (SQLite):**
113
-
114
- ```typescript
115
- // Set DATA_PATH BEFORE importing bunqueue
116
- process.env.DATA_PATH = './data/bunqueue.db';
117
-
118
- import { Queue, Worker } from 'bunqueue/client';
119
-
120
- const queue = new Queue('emails', { embedded: true });
121
- const worker = new Worker('emails', processor, { embedded: true });
122
- ```
123
-
124
- > Without `DATA_PATH`, bunqueue runs in-memory (no persistence across restarts).
125
-
126
- ### Server Mode
127
-
128
- For multi-process or microservice architectures.
129
-
130
- **Terminal 1 - Start server:**
131
- ```bash
132
- bunqueue start
133
- ```
134
-
135
- <img src=".github/terminal.png" alt="bunqueue server running" width="600" />
136
-
137
- **Terminal 2 - Producer:**
138
- ```typescript
139
- const res = await fetch('http://localhost:6790/push', {
140
- method: 'POST',
141
- headers: { 'Content-Type': 'application/json' },
142
- body: JSON.stringify({
143
- queue: 'emails',
144
- data: { to: 'user@example.com' }
145
- })
146
- });
147
- ```
148
-
149
- **Terminal 3 - Consumer:**
150
- ```typescript
151
- while (true) {
152
- const res = await fetch('http://localhost:6790/pull', {
153
- method: 'POST',
154
- body: JSON.stringify({ queue: 'emails', timeout: 5000 })
155
- });
156
-
157
- const job = await res.json();
158
- if (job.id) {
159
- console.log('Processing:', job.data);
160
- await fetch('http://localhost:6790/ack', {
161
- method: 'POST',
162
- body: JSON.stringify({ id: job.id })
163
- });
164
- }
165
- }
166
- ```
167
-
168
- ---
169
-
170
- ## Features
171
-
172
- - **Blazing Fast** β€” 500K+ jobs/sec, built on Bun runtime
173
- - **Dual Mode** β€” Embedded (in-process) or Server (TCP/HTTP)
174
- - **BullMQ-Compatible API** β€” Easy migration with `Queue`, `Worker`, `QueueEvents`
175
- - **Persistent Storage** β€” SQLite with WAL mode
176
- - **Sandboxed Workers** β€” Isolated processes for crash protection
177
- - **Priority Queues** β€” FIFO, LIFO, and priority-based ordering
178
- - **Delayed Jobs** β€” Schedule jobs for later
179
- - **Repeatable Jobs** β€” Recurring jobs with interval and limit
180
- - **Cron Scheduling** β€” Recurring jobs with cron expressions
181
- - **Queue Groups** β€” Organize queues in namespaces
182
- - **Flow/Pipelines** β€” Chain jobs A β†’ B β†’ C with result passing
183
- - **Retry & Backoff** β€” Automatic retries with exponential backoff
184
- - **Dead Letter Queue** β€” Failed jobs preserved for inspection
185
- - **Job Dependencies** β€” Parent-child relationships
186
- - **Progress Tracking** β€” Real-time progress updates
187
- - **Rate Limiting** β€” Per-queue rate limits
188
- - **Webhooks** β€” HTTP callbacks on job events
189
- - **Real-time Events** β€” WebSocket and SSE support
190
- - **Prometheus Metrics** β€” Built-in monitoring
191
- - **Full CLI** β€” Manage queues from command line
192
-
193
- ---
194
-
195
- ## Embedded Mode
196
-
197
- > **Important:** Both `Queue` and `Worker` require `embedded: true` to work in embedded mode.
198
- > Without it, they default to TCP mode and try to connect to a bunqueue server.
199
-
200
- ### Queue API
201
-
202
- ```typescript
203
- import { Queue } from 'bunqueue/client';
204
-
205
- const queue = new Queue('my-queue', { embedded: true });
206
-
207
- // Add job
208
- const job = await queue.add('task-name', { data: 'value' });
209
-
210
- // Add with options
211
- await queue.add('task', { data: 'value' }, {
212
- priority: 10, // Higher = processed first
213
- delay: 5000, // Delay in ms
214
- attempts: 3, // Max retries
215
- backoff: 1000, // Backoff base (ms)
216
- timeout: 30000, // Processing timeout
217
- jobId: 'unique-id', // Custom ID
218
- removeOnComplete: true,
219
- removeOnFail: false,
220
- });
221
-
222
- // Bulk add
223
- await queue.addBulk([
224
- { name: 'task1', data: { id: 1 } },
225
- { name: 'task2', data: { id: 2 } },
226
- ]);
227
-
228
- // Get job
229
- const job = await queue.getJob('job-id');
230
-
231
- // Remove job
232
- await queue.remove('job-id');
233
-
234
- // Get counts
235
- const counts = await queue.getJobCounts();
236
- // { waiting: 10, active: 2, completed: 100, failed: 5 }
237
-
238
- // Queue control
239
- await queue.pause();
240
- await queue.resume();
241
- await queue.drain(); // Remove waiting jobs
242
- await queue.obliterate(); // Remove ALL data
243
- ```
244
-
245
- ### Worker API
246
-
247
- ```typescript
248
- import { Worker } from 'bunqueue/client';
249
-
250
- const worker = new Worker('my-queue', async (job) => {
251
- console.log('Processing:', job.name, job.data);
252
-
253
- // Update progress
254
- await job.updateProgress(50, 'Halfway done');
255
-
256
- // Add log
257
- await job.log('Processing step completed');
258
-
259
- // Return result
260
- return { success: true };
261
- }, {
262
- embedded: true, // Required for embedded mode
263
- concurrency: 10, // Parallel jobs
264
- autorun: true, // Start automatically
265
- });
266
-
267
- // Events
268
- worker.on('active', (job) => {
269
- console.log(`Job ${job.id} started`);
270
- });
271
-
272
- worker.on('completed', (job, result) => {
273
- console.log(`Job ${job.id} completed:`, result);
274
- });
275
-
276
- worker.on('failed', (job, err) => {
277
- console.error(`Job ${job.id} failed:`, err.message);
278
- });
279
-
280
- worker.on('progress', (job, progress) => {
281
- console.log(`Job ${job.id} progress:`, progress);
282
- });
283
-
284
- worker.on('error', (err) => {
285
- console.error('Worker error:', err);
286
- });
287
-
288
- // Control
289
- worker.pause();
290
- worker.resume();
291
- await worker.close(); // Graceful shutdown
292
- await worker.close(true); // Force close
293
- ```
294
-
295
- ### SandboxedWorker
296
-
297
- Run job processors in **isolated Bun Worker processes**. Perfect for:
298
- - CPU-intensive tasks that would block the event loop
299
- - Processing untrusted code/data
300
- - Jobs that might crash or have memory leaks
301
- - Workloads requiring process-level isolation
302
-
303
- ```typescript
304
- import { Queue, SandboxedWorker } from 'bunqueue/client';
305
-
306
- const queue = new Queue('image-processing');
307
-
308
- // Create sandboxed worker pool
309
- const worker = new SandboxedWorker('image-processing', {
310
- processor: './imageProcessor.ts', // Runs in separate process
311
- concurrency: 4, // 4 parallel worker processes
312
- timeout: 60000, // 60s timeout per job
313
- maxMemory: 256, // MB per worker (uses smol mode if ≀64)
314
- maxRestarts: 10, // Auto-restart crashed workers
315
- });
316
-
317
- worker.start();
318
-
319
- // Add jobs normally
320
- await queue.add('resize', {
321
- image: 'photo.jpg',
322
- width: 800
323
- });
324
-
325
- // Check worker stats
326
- const stats = worker.getStats();
327
- // { total: 4, busy: 2, idle: 2, restarts: 0 }
328
-
329
- // Graceful shutdown
330
- await worker.stop();
331
- ```
332
-
333
- **Processor file** (`imageProcessor.ts`):
334
- ```typescript
335
- // This runs in an isolated Bun Worker process
336
- export default async (job: {
337
- id: string;
338
- data: any;
339
- queue: string;
340
- attempts: number;
341
- progress: (value: number) => void;
342
- }) => {
343
- job.progress(10);
344
-
345
- // CPU-intensive work - won't block main process
346
- const result = await processImage(job.data.image, job.data.width);
347
-
348
- job.progress(100);
349
- return { processed: true, path: result };
350
- };
351
- ```
352
-
353
- **Comparison:**
354
-
355
- | Feature | Worker | SandboxedWorker |
356
- |---------|--------|-----------------|
357
- | Execution | In-process | Separate process |
358
- | Latency | ~0.002ms | ~2-5ms (IPC overhead) |
359
- | Crash isolation | ❌ | βœ… |
360
- | Memory leak protection | ❌ | βœ… |
361
- | CPU-bound safety | ❌ Blocks event loop | βœ… Isolated |
362
- | Use case | Fast I/O tasks | Heavy computation |
363
-
364
- ### QueueEvents
365
-
366
- Listen to queue events without processing jobs.
367
-
368
- ```typescript
369
- import { QueueEvents } from 'bunqueue/client';
370
-
371
- const events = new QueueEvents('my-queue');
372
-
373
- events.on('waiting', ({ jobId }) => {
374
- console.log(`Job ${jobId} waiting`);
375
- });
376
-
377
- events.on('active', ({ jobId }) => {
378
- console.log(`Job ${jobId} active`);
379
- });
380
-
381
- events.on('completed', ({ jobId, returnvalue }) => {
382
- console.log(`Job ${jobId} completed:`, returnvalue);
383
- });
384
-
385
- events.on('failed', ({ jobId, failedReason }) => {
386
- console.log(`Job ${jobId} failed:`, failedReason);
387
- });
388
-
389
- events.on('progress', ({ jobId, data }) => {
390
- console.log(`Job ${jobId} progress:`, data);
391
- });
392
-
393
- await events.close();
394
- ```
395
-
396
- ### Repeatable Jobs
397
-
398
- Jobs that repeat automatically at fixed intervals.
399
-
400
- ```typescript
401
- import { Queue, Worker } from 'bunqueue/client';
402
-
403
- const queue = new Queue('heartbeat');
404
-
405
- // Repeat every 5 seconds, max 10 times
406
- await queue.add('ping', { timestamp: Date.now() }, {
407
- repeat: {
408
- every: 5000, // 5 seconds
409
- limit: 10, // max 10 repetitions
410
- }
411
- });
412
-
413
- // Infinite repeat (no limit)
414
- await queue.add('health-check', {}, {
415
- repeat: { every: 60000 } // every minute, forever
416
- });
417
-
418
- const worker = new Worker('heartbeat', async (job) => {
419
- console.log('Heartbeat:', job.data);
420
- return { ok: true };
421
- });
422
- ```
423
-
424
- ### Queue Groups
425
-
426
- Organize queues with namespaces.
427
-
428
- ```typescript
429
- import { QueueGroup } from 'bunqueue/client';
430
-
431
- // Create a group with namespace
432
- const billing = new QueueGroup('billing');
433
-
434
- // Get queues (automatically prefixed)
435
- const invoices = billing.getQueue('invoices'); // β†’ "billing:invoices"
436
- const payments = billing.getQueue('payments'); // β†’ "billing:payments"
437
-
438
- // Get workers for the group
439
- const worker = billing.getWorker('invoices', async (job) => {
440
- console.log('Processing invoice:', job.data);
441
- return { processed: true };
442
- });
443
-
444
- // List all queues in the group
445
- const queues = billing.listQueues(); // ['invoices', 'payments']
446
-
447
- // Bulk operations on the group
448
- billing.pauseAll();
449
- billing.resumeAll();
450
- billing.drainAll();
451
- ```
452
-
453
- ### FlowProducer (Pipelines)
454
-
455
- Chain jobs with dependencies and result passing.
456
-
457
- ```typescript
458
- import { FlowProducer, Worker } from 'bunqueue/client';
459
-
460
- const flow = new FlowProducer();
461
-
462
- // Chain: A β†’ B β†’ C (sequential execution)
463
- const { jobIds } = await flow.addChain([
464
- { name: 'fetch', queueName: 'pipeline', data: { url: 'https://api.example.com' } },
465
- { name: 'process', queueName: 'pipeline', data: {} },
466
- { name: 'store', queueName: 'pipeline', data: {} },
467
- ]);
468
-
469
- // Parallel then merge: [A, B, C] β†’ D
470
- const result = await flow.addBulkThen(
471
- [
472
- { name: 'fetch-1', queueName: 'parallel', data: { source: 'api1' } },
473
- { name: 'fetch-2', queueName: 'parallel', data: { source: 'api2' } },
474
- { name: 'fetch-3', queueName: 'parallel', data: { source: 'api3' } },
475
- ],
476
- { name: 'merge', queueName: 'parallel', data: {} }
477
- );
478
-
479
- // Tree structure
480
- await flow.addTree({
481
- name: 'root',
482
- queueName: 'tree',
483
- data: { level: 0 },
484
- children: [
485
- { name: 'child1', queueName: 'tree', data: { level: 1 } },
486
- { name: 'child2', queueName: 'tree', data: { level: 1 } },
487
- ],
488
- });
489
-
490
- // Worker with parent result access
491
- const worker = new Worker('pipeline', async (job) => {
492
- if (job.name === 'fetch') {
493
- const data = await fetchData(job.data.url);
494
- return { data };
495
- }
496
-
497
- if (job.name === 'process' && job.data.__flowParentId) {
498
- // Get result from previous job in chain
499
- const parentResult = flow.getParentResult(job.data.__flowParentId);
500
- return { processed: transform(parentResult.data) };
501
- }
502
-
503
- return { done: true };
504
- });
505
- ```
506
-
507
- ### Multi-File Setup
508
-
509
- When using bunqueue across multiple files, ensure `DATA_PATH` is set before any imports:
510
-
511
- **main.ts:**
512
- ```typescript
513
- // 1. Set DATA_PATH FIRST (before any bunqueue imports)
514
- import { mkdirSync } from 'fs';
515
- mkdirSync('./data', { recursive: true });
516
- process.env.DATA_PATH = './data/bunqueue.db';
517
-
518
- // 2. Then import your queue module
519
- import { recoverJobs, startWorker } from './queue';
520
-
521
- // 3. Start worker and recover jobs
522
- startWorker();
523
- await recoverJobs();
524
- ```
525
-
526
- **queue.ts:**
527
- ```typescript
528
- import { Queue, Worker } from 'bunqueue/client';
529
-
530
- const queue = new Queue<{ id: string }>('tasks', { embedded: true });
531
-
532
- const worker = new Worker<{ id: string }>('tasks', async (job) => {
533
- console.log('Processing:', job.data.id);
534
- return { success: true };
535
- }, {
536
- embedded: true,
537
- autorun: false, // Don't start automatically
538
- });
539
-
540
- export function startWorker() {
541
- worker.run();
542
- }
543
-
544
- export async function recoverJobs() {
545
- // Your recovery logic
546
- await queue.add('task', { id: 'job-1' });
547
- }
548
-
549
- export { queue, worker };
550
- ```
551
-
552
- > **Why `autorun: false`?** When `autorun: true` (default), the Worker starts polling immediately on import.
553
- > If `DATA_PATH` isn't set yet, bunqueue uses in-memory mode. Use `autorun: false` and call `worker.run()` manually after setup.
554
-
555
- ### Shutdown
556
-
557
- ```typescript
558
- import { shutdownManager } from 'bunqueue/client';
559
-
560
- // Cleanup when done
561
- shutdownManager();
562
- ```
563
-
564
- ### Troubleshooting
565
-
566
- **"Command timeout" error:**
567
- ```
568
- error: Command timeout
569
- queue: "my-queue",
570
- context: "pull"
571
- ```
572
- This means your Worker is in TCP mode (trying to connect to a server) instead of embedded mode.
573
- **Fix:** Add `embedded: true` to your Worker options.
574
-
575
- **SQLite database not created:**
576
- - Set `DATA_PATH` environment variable before importing bunqueue
577
- - Ensure the directory exists: `mkdirSync('./data', { recursive: true })`
578
- - Without `DATA_PATH`, bunqueue runs in-memory (no persistence)
579
-
580
- **Jobs not being processed:**
581
- - Ensure both Queue AND Worker have `embedded: true`
582
- - Check Worker is running: use `worker.run()` if `autorun: false`
583
-
584
- ---
585
-
586
- ## Server Mode
587
-
588
- ### Start Server
589
-
590
- ```bash
591
- # Basic
592
- bunqueue start
593
-
594
- # With options
595
- bunqueue start --tcp-port 6789 --http-port 6790 --data-path ./data/queue.db
596
-
597
- # With environment variables
598
- DATA_PATH=./data/bunqueue.db AUTH_TOKENS=secret bunqueue start
599
- ```
600
-
601
- ### Environment Variables
602
-
603
- ```env
604
- TCP_PORT=6789
605
- HTTP_PORT=6790
606
- HOST=0.0.0.0
607
- DATA_PATH=./data/bunqueue.db
608
- AUTH_TOKENS=token1,token2
609
- ```
610
-
611
- ### HTTP API
612
-
613
- ```bash
614
- # Push job
615
- curl -X POST http://localhost:6790/push \
616
- -H "Content-Type: application/json" \
617
- -d '{"queue":"emails","data":{"to":"user@test.com"},"priority":10}'
618
-
619
- # Pull job
620
- curl -X POST http://localhost:6790/pull \
621
- -H "Content-Type: application/json" \
622
- -d '{"queue":"emails","timeout":5000}'
623
-
624
- # Acknowledge
625
- curl -X POST http://localhost:6790/ack \
626
- -H "Content-Type: application/json" \
627
- -d '{"id":"job-id","result":{"sent":true}}'
628
-
629
- # Fail
630
- curl -X POST http://localhost:6790/fail \
631
- -H "Content-Type: application/json" \
632
- -d '{"id":"job-id","error":"Failed to send"}'
633
-
634
- # Stats
635
- curl http://localhost:6790/stats
636
-
637
- # Health
638
- curl http://localhost:6790/health
639
-
640
- # Prometheus metrics
641
- curl http://localhost:6790/prometheus
642
- ```
643
-
644
- ### TCP Protocol
645
-
646
- ```bash
647
- nc localhost 6789
648
-
649
- # Commands (JSON)
650
- {"cmd":"PUSH","queue":"tasks","data":{"action":"process"}}
651
- {"cmd":"PULL","queue":"tasks","timeout":5000}
652
- {"cmd":"ACK","id":"1","result":{"done":true}}
653
- {"cmd":"FAIL","id":"1","error":"Something went wrong"}
654
- ```
655
-
656
- ---
657
-
658
- ## CLI
659
-
660
- ```bash
661
- # Server
662
- bunqueue start
663
- bunqueue start --tcp-port 6789 --http-port 6790
664
-
665
- # Jobs
666
- bunqueue push emails '{"to":"user@test.com"}'
667
- bunqueue push tasks '{"action":"sync"}' --priority 10 --delay 5000
668
- bunqueue pull emails --timeout 5000
669
- bunqueue ack <job-id>
670
- bunqueue fail <job-id> --error "Failed"
671
-
672
- # Job management
673
- bunqueue job get <id>
674
- bunqueue job progress <id> 50 --message "Processing"
675
- bunqueue job cancel <id>
676
-
677
- # Queue control
678
- bunqueue queue list
679
- bunqueue queue pause emails
680
- bunqueue queue resume emails
681
- bunqueue queue drain emails
682
-
683
- # Cron
684
- bunqueue cron list
685
- bunqueue cron add cleanup -q maintenance -d '{}' -s "0 * * * *"
686
- bunqueue cron delete cleanup
687
-
688
- # DLQ
689
- bunqueue dlq list emails
690
- bunqueue dlq retry emails
691
- bunqueue dlq purge emails
692
-
693
- # Monitoring
694
- bunqueue stats
695
- bunqueue metrics
696
- bunqueue health
697
-
698
- # Backup (S3)
699
- bunqueue backup now
700
- bunqueue backup list
701
- bunqueue backup restore <key> --force
702
- ```
703
-
704
- ---
705
-
706
- ## Docker
707
-
708
- ```bash
709
- # Run
710
- docker run -p 6789:6789 -p 6790:6790 ghcr.io/egeominotti/bunqueue
711
-
712
- # With persistence
713
- docker run -p 6789:6789 -p 6790:6790 \
714
- -v bunqueue-data:/app/data \
715
- -e DATA_PATH=/app/data/bunqueue.db \
716
- ghcr.io/egeominotti/bunqueue
717
-
718
- # With auth
719
- docker run -p 6789:6789 -p 6790:6790 \
720
- -e AUTH_TOKENS=secret \
721
- ghcr.io/egeominotti/bunqueue
722
- ```
723
-
724
- ### Docker Compose
725
-
726
- ```yaml
727
- version: "3.8"
728
- services:
729
- bunqueue:
730
- image: ghcr.io/egeominotti/bunqueue
731
- ports:
732
- - "6789:6789"
733
- - "6790:6790"
734
- volumes:
735
- - bunqueue-data:/app/data
736
- environment:
737
- - DATA_PATH=/app/data/bunqueue.db
738
- - AUTH_TOKENS=your-secret-token
739
-
740
- volumes:
741
- bunqueue-data:
742
- ```
743
-
744
- ---
745
-
746
- ## S3 Backup
747
-
748
- ```env
749
- S3_BACKUP_ENABLED=1
750
- S3_ACCESS_KEY_ID=your-key
751
- S3_SECRET_ACCESS_KEY=your-secret
752
- S3_BUCKET=my-bucket
753
- S3_REGION=us-east-1
754
- S3_BACKUP_INTERVAL=21600000 # 6 hours
755
- S3_BACKUP_RETENTION=7
756
- ```
757
-
758
- Supported providers: AWS S3, Cloudflare R2, MinIO, DigitalOcean Spaces.
759
-
760
- ---
761
-
762
- ## When to Use What?
763
-
764
- | Scenario | Mode |
765
- |----------|------|
766
- | Single app, monolith | **Embedded** |
767
- | Scripts, CLI tools | **Embedded** |
768
- | Serverless (with persistence) | **Embedded** |
769
- | Microservices | **Server** |
770
- | Multiple languages | **Server** (HTTP API) |
771
- | Horizontal scaling | **Server** |
772
-
773
- ### Server Mode SDK
774
-
775
- For communicating with bunqueue server from **separate processes**, use the [flashq](https://www.npmjs.com/package/flashq) SDK:
776
-
777
- ```bash
778
- bun add flashq
779
- ```
780
-
781
- ```typescript
782
- import { FlashQ } from 'flashq';
783
-
784
- const client = new FlashQ({ host: 'localhost', port: 6789 });
785
-
786
- // Push job
787
- await client.push('emails', { to: 'user@test.com' });
788
-
789
- // Pull and process
790
- const job = await client.pull('emails');
791
- if (job) {
792
52
  console.log('Processing:', job.data);
793
- await client.ack(job.id);
794
- }
795
- ```
796
-
797
- | Package | Use Case |
798
- |---------|----------|
799
- | `bunqueue/client` | Same process (embedded) |
800
- | `flashq` | Different process (TCP client) |
801
-
802
- ```
803
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
804
- β”‚ Your App β”‚ β”‚ Your App β”‚
805
- β”‚ β”‚ β”‚ β”‚
806
- β”‚ bunqueue/clientβ”‚ β”‚ flashq β”‚
807
- β”‚ (embedded) β”‚ β”‚ (TCP client) β”‚
808
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
809
- β”‚ β”‚
810
- β”‚ β–Ό
811
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
812
- β”‚ β”‚ bunqueue server β”‚
813
- β”‚ β”‚ (port 6789) β”‚
814
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
815
- β”‚
816
- Same process Different process
817
- ```
818
-
819
- ---
820
-
821
- ## Architecture
53
+ return { sent: true };
54
+ }, { embedded: true });
822
55
 
56
+ await queue.add('welcome', { to: 'user@example.com' });
823
57
  ```
824
- β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
825
- β”‚ bunqueue β”‚
826
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
827
- β”‚ Embedded Mode β”‚ Server Mode β”‚
828
- β”‚ (bunqueue/client) β”‚ (bunqueue start) β”‚
829
- β”‚ β”‚ β”‚
830
- β”‚ Queue, Worker β”‚ TCP (6789) + HTTP (6790) β”‚
831
- β”‚ in-process β”‚ multi-process β”‚
832
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
833
- β”‚ Core Engine β”‚
834
- β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
835
- β”‚ β”‚ Queues β”‚ β”‚ Workers β”‚ β”‚ Scheduler β”‚ β”‚ DLQ β”‚ β”‚
836
- β”‚ β”‚(32 shards)β”‚ β”‚ β”‚ β”‚ (Cron) β”‚ β”‚ β”‚ β”‚
837
- β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
838
- β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
839
- β”‚ SQLite (WAL mode, 256MB mmap) β”‚
840
- β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
841
- ```
842
-
843
- ---
844
58
 
845
- ## Contributing
59
+ ## Documentation
846
60
 
847
- ```bash
848
- bun install
849
- bun test
850
- bun run lint
851
- bun run format
852
- bun run check
853
- ```
61
+ **[Read the full documentation β†’](https://egeominotti.github.io/bunqueue/)**
854
62
 
855
- ---
63
+ - [Quick Start](https://egeominotti.github.io/bunqueue/guide/quickstart/)
64
+ - [Queue API](https://egeominotti.github.io/bunqueue/guide/queue/)
65
+ - [Worker API](https://egeominotti.github.io/bunqueue/guide/worker/)
66
+ - [Server Mode](https://egeominotti.github.io/bunqueue/guide/server/)
67
+ - [CLI Reference](https://egeominotti.github.io/bunqueue/guide/cli/)
68
+ - [Environment Variables](https://egeominotti.github.io/bunqueue/guide/env-vars/)
856
69
 
857
70
  ## License
858
71
 
859
- MIT License β€” see [LICENSE](LICENSE) for details.
860
-
861
- ---
862
-
863
- <p align="center">
864
- Built with <a href="https://bun.sh">Bun</a> πŸ₯Ÿ
865
- </p>
72
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bunqueue",
3
- "version": "1.9.4",
3
+ "version": "1.9.5",
4
4
  "description": "High-performance job queue server written in Bun. SQLite persistence, cron scheduling, priorities, retries, DLQ, webhooks. Minimal dependencies.",
5
5
  "type": "module",
6
6
  "main": "dist/main.js",