queen-mq 0.1.0 → 0.1.1

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 CHANGED
@@ -1,40 +1,117 @@
1
- # Queen - High-Performance Message Queue System
1
+ # Queen - PostgreSQL-backed Message Queue System
2
2
 
3
- A modern, high-performance message queue system built with PostgreSQL and uWebSockets.js, featuring priority-based processing, advanced scheduling, and real-time monitoring.
3
+ <div align="center">
4
+
5
+ **A modern, high-performance message queue system built on PostgreSQL**
6
+
7
+ [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE.md)
8
+ [![Node](https://img.shields.io/badge/node-%3E%3D22.0.0-brightgreen.svg)](https://nodejs.org/)
9
+
10
+ [Quick Start](#-quick-start) • [Client Examples](#-client-examples) • [Server Setup](#-server-setup) • [Core Concepts](#-core-concepts) • [API Reference](#-http-api-reference) • [Dashboard](#-dashboard)
11
+
12
+ </div>
4
13
 
5
14
  ![Queen Dashboard](assets/dashboard.png)
6
15
 
7
- ## 🚀 Features
16
+ ---
17
+
18
+ ## 🎯 Introduction
19
+
20
+ **Queen** is a production-ready message queue system that combines the reliability of PostgreSQL with the performance of modern async architectures. Built with uWebSockets.js for blazing-fast HTTP handling and designed for real-world workloads.
21
+
22
+ ### Why Queen?
8
23
 
9
- - **🏗️ Flexible Architecture**: Queues → Partitions → Messages with optional namespace/task grouping
10
- - **⚡ Priority Processing**: Queue and partition-level priorities with FIFO within partitions
11
- - **🕒 Advanced Scheduling**: Delayed processing and window buffering
12
- - **🔄 Reliable Processing**: Lease-based processing with automatic retry and dead letter queues
13
- - **📊 Real-time Monitoring**: WebSocket dashboard with live metrics and analytics
14
- - **🔒 Message Guarantees**: ACID transactions, idempotency, and no message loss
15
- - **🚄 High Performance**: 10,000+ messages/second with sub-10ms latency
16
- - **🌐 Long Polling**: Event-driven optimization for real-time message consumption
17
- - **📦 Batch Operations**: Efficient bulk message processing with individual and batch consumer modes
18
- - **🛠️ Client SDK**: Full-featured JavaScript client with retry logic and helpers
24
+ **🚀 Developer-First API**
25
+ - **4 methods, infinite patterns**: `queue()`, `push()`, `take()`, `ack()`
26
+ - **Async iteration**: Process messages with familiar `for await` syntax
27
+ - **Smart addressing**: `orders/urgent@workers` - queue, partition, and consumer group in one
28
+
29
+ **⚡ Production-Ready Performance**
30
+ - **10,000+ msg/sec** throughput with sub-10ms latency
31
+ - **Long polling** for event-driven, real-time message delivery
32
+ - **Partition locking** prevents duplicate processing across consumers
33
+ - **Connection pooling** and optimized batch operations
34
+
35
+ **🏗️ Flexible Architecture**
36
+ - **Queue Mode**: Competitive consumption (traditional work queue)
37
+ - **Bus Mode**: Pub/sub with consumer groups (event streaming)
38
+ - **Mixed Mode**: Combine both patterns in the same system
39
+ - **Partitions**: FIFO ordering with parallel processing
40
+
41
+ **🔒 Enterprise Features**
42
+ - **AES-256-GCM Encryption**: Protect sensitive data at rest
43
+ - **Message Retention**: Automatic cleanup policies
44
+ - **Message Eviction**: SLA enforcement for time-sensitive tasks
45
+ - **Dead Letter Queue**: Handle failed messages gracefully
46
+
47
+ **📊 Built-in Observability**
48
+ - **Real-time Dashboard**: WebSocket-powered monitoring
49
+ - **Rich Analytics**: Throughput, lag, queue depth metrics
50
+ - **Message Browser**: Search, inspect, and retry messages
51
+ - **System Health**: Database, memory, and performance metrics
52
+
53
+ ### Use Cases
54
+
55
+ - **Task Queues**: Background jobs, email sending, data processing
56
+ - **Event Streaming**: Audit logs, analytics, multi-service event handling
57
+ - **Workflow Orchestration**: Multi-stage pipelines, saga patterns
58
+ - **Rate Limiting**: Throttle and batch time-sensitive operations
59
+ - **Priority Processing**: Handle urgent tasks before routine ones
60
+
61
+ ---
19
62
 
20
63
  ## 📋 Table of Contents
21
64
 
22
- - [Quick Start](#quick-start)
23
- - [Architecture](#architecture)
24
- - [Core Concepts](#core-concepts)
25
- - [API Reference](#api-reference)
26
- - [Client SDK](#client-sdk)
27
- - [Dashboard](#dashboard)
28
- - [Examples](#examples)
29
- - [Performance](#performance)
30
- - [Configuration](#configuration)
65
+ - [First Queue](#-first-queue)
66
+ - [Quick Start](#-quick-start)
67
+ - [Client Examples](#-client-examples)
68
+ - [Server Setup](#-server-setup)
69
+ - [Core Concepts](#-core-concepts)
70
+ - [HTTP API Reference](#-http-api-reference)
71
+ - [Dashboard](#-dashboard)
72
+ - [Configuration](#-configuration)
73
+ - [Full Examples](#-full-examples)
74
+ - [Testing](#-testing)
75
+ - [Contributing](#-contributing)
76
+
77
+ ---
78
+
79
+ ## First Queue
80
+
81
+ ```javascript
82
+ import { Queen } from 'queen-mq';
83
+
84
+ const client = new Queen({
85
+ baseUrls: ['http://localhost:6632']
86
+ });
87
+
88
+ // Configure queue
89
+ await client.queue('tasks', {
90
+ leaseTime: 300,
91
+ retryLimit: 3
92
+ });
93
+
94
+ // Push a message
95
+ await client.push('tasks', {
96
+ action: 'send-email',
97
+ to: 'user@example.com'
98
+ });
99
+
100
+ // Process messages
101
+ for await (const message of client.take('tasks')) {
102
+ console.log('Processing:', message.data);
103
+ await client.ack(message);
104
+ }
105
+ ```
106
+
107
+ That's it! You now have a working message queue system.
31
108
 
32
109
  ## 🏃 Quick Start
33
110
 
34
111
  ### Prerequisites
35
112
 
36
- - Node.js 22+
37
- - PostgreSQL 12+
113
+ - **Node.js 22+**
114
+ - **PostgreSQL 12+**
38
115
 
39
116
  ### Installation
40
117
 
@@ -47,556 +124,788 @@ cd queen
47
124
  nvm use 22
48
125
  npm install
49
126
 
50
- # Set up environment (optional)
127
+ # Initialize database schema
128
+ node init-db.js
129
+ ```
130
+
131
+ ### Set Environment (Optional)
132
+
133
+ ```bash
134
+ # Database connection
51
135
  export PG_USER=postgres
52
136
  export PG_HOST=localhost
53
137
  export PG_DB=postgres
54
138
  export PG_PASSWORD=postgres
55
139
  export PG_PORT=5432
140
+
141
+ # Enable encryption (optional)
142
+ export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
56
143
  ```
57
144
 
58
- ### Database Setup
145
+ ### Start the Server
59
146
 
60
147
  ```bash
61
- # Initialize the database schema
62
- node init-db.js
148
+ npm start
149
+ # Server starts on http://localhost:6632
63
150
  ```
64
151
 
65
- ### Start the Server
152
+ ---
66
153
 
67
- ```bash
68
- # Optional: Enable encryption
69
- export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
154
+ ## 💻 Client Examples
70
155
 
71
- # Start the Queen server
72
- npm start
73
- # Or use the startup script
74
- ./start.sh
156
+ The Queen client provides a minimalist API with just 4 methods that compose into any messaging pattern you need.
75
157
 
76
- # Server starts on http://localhost:6632
158
+ ### Installation
159
+
160
+ ```bash
161
+ npm install queen-mq
77
162
  ```
78
163
 
79
164
  ### Basic Usage
80
165
 
166
+ #### 1. Configure a Queue
167
+
81
168
  ```javascript
82
- import { createQueenClient } from '@dev.smartpricing/queen'
169
+ import { Queen } from 'queen-mq';
170
+
171
+ const client = new Queen({
172
+ baseUrls: ['http://localhost:6632'],
173
+ timeout: 30000,
174
+ retryAttempts: 3
175
+ });
83
176
 
84
- const client = createQueenClient({
85
- baseUrl: 'http://localhost:6632'
177
+ // Configure with options
178
+ await client.queue('orders', {
179
+ priority: 10, // Higher priority queues processed first
180
+ leaseTime: 600, // 10 minutes to process each message
181
+ retryLimit: 3, // Retry up to 3 times
182
+ delayedProcessing: 0, // No delay (immediate processing)
86
183
  });
87
184
 
88
- // Push a message
89
- await client.push({
90
- items: [{
91
- queue: 'email-queue',
92
- partition: 'urgent',
93
- payload: { to: 'user@example.com', subject: 'Hello!' }
94
- }]
185
+ // Configure with namespace and task for grouping
186
+ await client.queue('order-processing', {
187
+ priority: 10
188
+ }, {
189
+ namespace: 'ecommerce',
190
+ task: 'checkout'
95
191
  });
192
+ ```
193
+
194
+ #### 2. Push Messages
96
195
 
97
- // Pop and process messages
98
- const result = await client.pop({
99
- queue: 'email-queue',
100
- batch: 10,
101
- wait: true
196
+ ```javascript
197
+ // Single message
198
+ await client.push('orders', {
199
+ orderId: 12345,
200
+ amount: 99.99
102
201
  });
103
202
 
104
- for (const message of result.messages) {
105
- console.log('Processing:', message.data);
106
- await client.ack(message.transactionId, 'completed');
203
+ // To a specific partition
204
+ await client.push('orders/urgent', {
205
+ orderId: 12346,
206
+ amount: 999.99,
207
+ priority: 'high'
208
+ });
209
+
210
+ // Batch messages
211
+ await client.push('orders', [
212
+ { orderId: 12347, amount: 49.99 },
213
+ { orderId: 12348, amount: 79.99 },
214
+ { orderId: 12349, amount: 29.99 }
215
+ ]);
216
+
217
+ // With message properties
218
+ await client.push('orders', {
219
+ orderId: 12350,
220
+ amount: 199.99
221
+ }, {
222
+ transactionId: 'txn-12350', // For idempotency
223
+ traceId: '550e8400-e29b-41d4-a716-446655440000' // Valid UUID for tracing
224
+ });
225
+ ```
226
+
227
+ #### 3. Take Messages (Async Iterator)
228
+
229
+ ```javascript
230
+ // Process continuously with long polling
231
+ for await (const message of client.take('orders', {
232
+ wait: true, // Enable long polling
233
+ timeout: 30000, // 30 second timeout
234
+ batch: 10 // Fetch up to 10 at once
235
+ })) {
236
+ try {
237
+ await processOrder(message.data);
238
+ await client.ack(message); // Success
239
+ } catch (error) {
240
+ await client.ack(message, false, { error: error.message }); // Failure
241
+ }
242
+ }
243
+
244
+ // Process limited messages
245
+ for await (const message of client.take('orders', { limit: 100 })) {
246
+ await processOrder(message.data);
247
+ await client.ack(message);
248
+ }
249
+
250
+ // Take from specific partition
251
+ for await (const message of client.take('orders/urgent')) {
252
+ await processUrgentOrder(message.data);
253
+ await client.ack(message);
107
254
  }
108
255
  ```
109
256
 
110
- ## 🏗️ Architecture
257
+ #### 4. Acknowledge Messages
258
+
259
+ ```javascript
260
+ // Acknowledge success
261
+ await client.ack(message);
262
+ // or
263
+ await client.ack(message, true);
264
+
265
+ // Acknowledge failure (will retry based on retryLimit)
266
+ await client.ack(message, false);
111
267
 
112
- ### System Overview
268
+ // Acknowledge with error context
269
+ await client.ack(message, false, {
270
+ error: 'Payment gateway timeout'
271
+ });
272
+
273
+ // Acknowledge using transaction ID
274
+ await client.ack('4dfb0478-655b-4c91-bcd9-b7acacf0400f', true);
113
275
 
276
+ // Request explicit retry
277
+ await client.ack(message, 'retry');
114
278
  ```
115
- ┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
116
- │ Client SDK │───▶│ Queen Server │───▶│ PostgreSQL │
117
- └─────────────────┘ └──────────────────┘ └─────────────────┘
118
- │
119
- ▼
120
- ┌──────────────────┐
121
- │ Dashboard UI │
122
- └──────────────────┘
279
+
280
+ ### Address Notation
281
+
282
+ Queen uses a simple addressing scheme that encodes queue, partition, and consumer group:
283
+
284
+ ```javascript
285
+ // Basic addresses
286
+ 'orders' // Queue (Default partition)
287
+ 'orders/urgent' // Queue with specific partition
288
+ 'orders@workers' // Queue with consumer group (bus mode)
289
+ 'orders/urgent@workers' // Full address: queue + partition + group
290
+
291
+ // Namespace/task filtering (cross-queue consumption)
292
+ 'namespace:ecommerce' // All queues in namespace
293
+ 'task:checkout' // All queues with task
294
+ 'namespace:ecommerce/task:checkout' // Combined filter
295
+ 'namespace:ecommerce/task:checkout@audit' // With consumer group
123
296
  ```
124
297
 
125
- ### Data Model
298
+ ### Consumer Patterns
299
+
300
+ #### Continuous Processing (Long Polling)
126
301
 
302
+ ```javascript
303
+ // Efficient real-time processing
304
+ for await (const message of client.take('tasks', {
305
+ wait: true, // Long polling - waits for messages
306
+ timeout: 30000 // Server timeout
307
+ })) {
308
+ await processTask(message.data);
309
+ await client.ack(message);
310
+ }
127
311
  ```
128
- Queues (with optional namespace/task grouping)
129
- └── Partitions (FIFO ordering, priority-based selection)
130
- └── Messages (lease-based processing)
312
+
313
+ #### Batch Processing
314
+
315
+ ```javascript
316
+ // Accumulate and process in batches
317
+ const batch = [];
318
+ for await (const message of client.take('analytics', { batch: 100 })) {
319
+ batch.push(message);
320
+
321
+ if (batch.length >= 100) {
322
+ await processBatch(batch.map(m => m.data));
323
+
324
+ // Acknowledge all
325
+ for (const msg of batch) {
326
+ await client.ack(msg);
327
+ }
328
+ batch.length = 0;
329
+ }
330
+ }
131
331
  ```
132
332
 
133
- **Database Schema:**
134
- - `queen.queues` - Top-level message containers with optional grouping
135
- - `queen.partitions` - Subdivisions within queues where FIFO is maintained
136
- - `queen.messages` - Individual messages with processing state
333
+ #### Parallel Processing with Partitions
137
334
 
138
- ### Key Components
335
+ ```javascript
336
+ // Create workers for parallel processing
337
+ const partitions = ['worker-1', 'worker-2', 'worker-3', 'worker-4'];
139
338
 
140
- - **uWebSockets.js Server**: High-performance HTTP/WebSocket server
141
- - **Queue Manager**: Core message processing logic with optimizations
142
- - **Resource Cache**: In-memory caching for queue/partition lookups
143
- - **Event Manager**: Real-time notifications for long polling
144
- - **WebSocket Server**: Live dashboard updates and monitoring
339
+ // Distribute messages across partitions
340
+ for (let i = 0; i < messages.length; i++) {
341
+ const partition = partitions[i % partitions.length];
342
+ await client.push(`tasks/${partition}`, messages[i]);
343
+ }
145
344
 
146
- ## 💡 Core Concepts
345
+ // Each worker processes its own partition (in parallel)
346
+ async function worker(partition) {
347
+ for await (const msg of client.take(`tasks/${partition}`)) {
348
+ await processTask(msg.data);
349
+ await client.ack(msg);
350
+ }
351
+ }
147
352
 
148
- ### Queues and Partitions
353
+ // Start all workers
354
+ await Promise.all(partitions.map(p => worker(p)));
355
+ ```
149
356
 
150
- **Queues** are the top-level organizational units. Each queue automatically gets a "Default" partition, and you can create additional partitions for different processing priorities or logical separation.
357
+ #### Consumer Groups (Bus Mode)
151
358
 
152
359
  ```javascript
153
- // Messages go to "Default" partition if not specified
154
- await client.push({
155
- items: [{ queue: 'orders', payload: { orderId: 123 } }]
156
- });
360
+ // Multiple services process the same messages independently
157
361
 
158
- // Explicit partition specification
159
- await client.push({
160
- items: [{
161
- queue: 'orders',
162
- partition: 'high-priority',
163
- payload: { orderId: 456, urgent: true }
164
- }]
165
- });
362
+ // Analytics service
363
+ for await (const event of client.take('events@analytics')) {
364
+ await updateAnalytics(event.data);
365
+ await client.ack(event, true, { group: 'analytics' });
366
+ }
367
+
368
+ // Monitoring service (gets same messages)
369
+ for await (const event of client.take('events@monitoring')) {
370
+ await checkThresholds(event.data);
371
+ await client.ack(event, true, { group: 'monitoring' });
372
+ }
373
+
374
+ // Audit service (also gets same messages)
375
+ for await (const event of client.take('events@audit')) {
376
+ await logToAudit(event.data);
377
+ await client.ack(event, true, { group: 'audit' });
378
+ }
166
379
  ```
167
380
 
168
- ### Priority Processing
381
+ #### Subscription Modes
382
+
383
+ ```javascript
384
+ // Start from all existing messages (replay)
385
+ for await (const event of client.take('events@replay-service', {
386
+ subscriptionMode: 'all'
387
+ })) {
388
+ await replayEvent(event.data);
389
+ await client.ack(event);
390
+ }
391
+
392
+ // Start from new messages only (real-time)
393
+ for await (const event of client.take('events@realtime', {
394
+ subscriptionMode: 'new'
395
+ })) {
396
+ await processEvent(event.data);
397
+ await client.ack(event);
398
+ }
169
399
 
170
- The system supports two levels of priority:
400
+ // Start from specific timestamp
401
+ for await (const event of client.take('events@historical', {
402
+ subscriptionMode: 'from',
403
+ subscriptionFrom: '2024-01-01T00:00:00Z'
404
+ })) {
405
+ await processHistoricalEvent(event.data);
406
+ await client.ack(event);
407
+ }
408
+ ```
171
409
 
172
- 1. **Queue Priority**: Higher priority queues are processed first
173
- 2. **FIFO Within Partitions**: Messages within the same partition are always processed in order
174
- 3. **Partitions**: Partitions are now simple FIFO containers - all configuration is at the queue level
410
+ #### Error Handling
175
411
 
176
412
  ```javascript
177
- // Configure queue with priority
178
- await client.configure({
179
- queue: 'orders',
180
- options: { priority: 10 } // Higher number = higher priority
181
- });
413
+ // Robust error handling with retries
414
+ for await (const message of client.take('critical-tasks')) {
415
+ let retries = 3;
416
+
417
+ while (retries > 0) {
418
+ try {
419
+ await processTask(message.data);
420
+ await client.ack(message);
421
+ break;
422
+ } catch (error) {
423
+ retries--;
424
+ if (retries === 0) {
425
+ console.error('Task failed after retries:', error);
426
+ await client.ack(message, false, { error: error.message });
427
+ } else {
428
+ await new Promise(r => setTimeout(r, 1000 * (4 - retries)));
429
+ }
430
+ }
431
+ }
432
+ }
182
433
  ```
183
434
 
184
- ### Message Lifecycle
435
+ #### Graceful Shutdown
436
+
437
+ ```javascript
438
+ let running = true;
439
+
440
+ process.on('SIGTERM', () => {
441
+ console.log('Shutting down gracefully...');
442
+ running = false;
443
+ });
185
444
 
445
+ for await (const message of client.take('orders')) {
446
+ if (!running) break;
447
+
448
+ await processOrder(message.data);
449
+ await client.ack(message);
450
+ }
451
+
452
+ await client.close();
453
+ console.log('Shutdown complete');
186
454
  ```
187
- pending → processing → completed/failed → (retry) → dead_letter
455
+
456
+ ---
457
+
458
+ ## 🖥️ Server Setup
459
+
460
+ ### Single Server
461
+
462
+ ```bash
463
+ # Start the server
464
+ npm start
465
+
466
+ # Or with custom configuration
467
+ PORT=6632 \
468
+ DB_POOL_SIZE=20 \
469
+ QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32) \
470
+ npm start
188
471
  ```
189
472
 
190
- 1. **Pending**: Message is queued and waiting to be processed
191
- 2. **Processing**: Message is leased to a worker (with timeout)
192
- 3. **Completed**: Message was successfully processed
193
- 4. **Failed**: Message processing failed (may retry based on configuration)
194
- 5. **Dead Letter**: Message exceeded retry limits
473
+ ### Multi-Server (Load Balanced)
195
474
 
196
- ### Lease-Based Processing
475
+ Queen supports running multiple servers for high availability and load distribution:
476
+
477
+ ```bash
478
+ # Server 1
479
+ PORT=6632 WORKER_ID=server-1 npm start
480
+
481
+ # Server 2
482
+ PORT=6633 WORKER_ID=server-2 npm start
483
+
484
+ # Server 3
485
+ PORT=6634 WORKER_ID=server-3 npm start
486
+ ```
197
487
 
198
- Messages are "leased" to workers for a specific duration. If not acknowledged within the lease time, they automatically return to pending status for retry.
488
+ Client configuration:
199
489
 
200
490
  ```javascript
201
- // Configure lease time (default: 300 seconds)
202
- await client.configure({
203
- queue: 'long-tasks',
204
- options: { leaseTime: 600 } // 10 minutes
491
+ const client = new Queen({
492
+ baseUrls: [
493
+ 'http://localhost:6632',
494
+ 'http://localhost:6633',
495
+ 'http://localhost:6634'
496
+ ],
497
+ loadBalancingStrategy: 'ROUND_ROBIN', // or 'RANDOM', 'LEAST_CONNECTIONS'
498
+ enableFailover: true
205
499
  });
206
500
  ```
207
501
 
208
- ## 🔐 Advanced Concepts
502
+ ### Docker Deployment
209
503
 
210
- ### Partition Locking
504
+ ```dockerfile
505
+ FROM node:22-alpine
506
+
507
+ WORKDIR /app
508
+ COPY package*.json ./
509
+ RUN npm ci --production
211
510
 
212
- Partition locking is a critical mechanism that ensures message processing isolation and prevents duplicate processing. When a consumer retrieves messages from a partition, that partition becomes "locked" to that consumer for the duration of the lease.
511
+ COPY . .
213
512
 
214
- #### How Partition Locking Works
513
+ EXPOSE 6632
514
+ CMD ["node", "src/server.js"]
515
+ ```
215
516
 
216
- 1. **Lock Acquisition**: When a consumer calls `pop()`, the system:
217
- - Checks for available messages in unlocked partitions
218
- - Acquires a lease on the partition(s) containing those messages
219
- - Records the lease with an expiration time based on the queue's `leaseTime`
517
+ ```yaml
518
+ # docker-compose.yml
519
+ version: '3.8'
220
520
 
221
- 2. **Lock Duration**: The partition remains locked until:
222
- - The consumer acknowledges all messages (releases the lock)
223
- - The lease expires (automatic release after `leaseTime` seconds)
224
- - The consumer explicitly releases the partition
521
+ services:
522
+ postgres:
523
+ image: postgres:16
524
+ environment:
525
+ POSTGRES_DB: queen
526
+ POSTGRES_USER: queen
527
+ POSTGRES_PASSWORD: queen
528
+ volumes:
529
+ - postgres_data:/var/lib/postgresql/data
530
+ ports:
531
+ - "5432:5432"
225
532
 
226
- 3. **Lock Scope**:
227
- - In **Queue Mode**: Each consumer gets a unique session, preventing any other consumer from accessing the same partition
228
- - In **Bus Mode**: Locks are per consumer group, allowing different groups to process the same messages independently
533
+ queen:
534
+ build: .
535
+ ports:
536
+ - "6632:6632"
537
+ environment:
538
+ PG_HOST: postgres
539
+ PG_DB: queen
540
+ PG_USER: queen
541
+ PG_PASSWORD: queen
542
+ DB_POOL_SIZE: 20
543
+ QUEEN_ENCRYPTION_KEY: ${QUEEN_ENCRYPTION_KEY}
544
+ depends_on:
545
+ - postgres
229
546
 
230
- ```javascript
231
- // Example: Two consumers in queue mode
232
- const consumer1 = await client.pop({ queue: 'orders' });
233
- // Consumer 1 gets messages from partition A and locks it
547
+ volumes:
548
+ postgres_data:
549
+ ```
550
+
551
+ ### Environment Variables
552
+
553
+ See the [Configuration](#-configuration) section for a complete list of environment variables.
234
554
 
235
- const consumer2 = await client.pop({ queue: 'orders' });
236
- // Consumer 2 gets messages from partition B (A is locked)
555
+ ### Database Schema
237
556
 
238
- // After Consumer 1 acknowledges:
239
- await client.ack(consumer1.messages[0].transactionId, 'completed');
240
- // Partition A is now unlocked and available
557
+ The database schema is automatically created when you run:
558
+
559
+ ```bash
560
+ node init-db.js
241
561
  ```
242
562
 
243
- ### FIFO Ordering Guarantees
563
+ This creates:
564
+ - `queen.queues` - Top-level message containers
565
+ - `queen.partitions` - Subdivisions within queues (FIFO ordering)
566
+ - `queen.messages` - Individual messages with processing state
244
567
 
245
- Queen provides strong FIFO (First-In-First-Out) ordering guarantees **within each partition**. This means:
568
+ ---
246
569
 
247
- #### Partition-Level FIFO
570
+ ## 💡 Core Concepts
248
571
 
249
- Messages within the same partition are always processed in the exact order they were received:
572
+ ### Architecture
250
573
 
251
- ```javascript
252
- // These messages will be processed in order 1, 2, 3
253
- await client.push({
254
- items: [
255
- { queue: 'tasks', partition: 'user-123', payload: { step: 1 } },
256
- { queue: 'tasks', partition: 'user-123', payload: { step: 2 } },
257
- { queue: 'tasks', partition: 'user-123', payload: { step: 3 } }
258
- ]
259
- });
574
+ Queen uses a two-tier architecture:
260
575
 
261
- // Consumer will always receive them in order 1, 2, 3
262
- const result = await client.pop({ queue: 'tasks', partition: 'user-123' });
576
+ ```
577
+ Queues (optional namespace/task grouping)
578
+ └── Partitions (FIFO ordering, parallel processing)
579
+ └── Messages (lease-based processing)
263
580
  ```
264
581
 
265
- #### Cross-Partition Ordering
582
+ **Key Principles:**
583
+ - **Configuration at queue level**: All settings (priority, lease time, retries) apply to the entire queue
584
+ - **FIFO within partitions**: Messages in the same partition are always processed in order
585
+ - **Partition locking**: Prevents duplicate processing across consumers
586
+ - **Lease-based processing**: Messages automatically return to pending if not acknowledged
266
587
 
267
- Messages in different partitions can be processed in parallel and have no ordering guarantees relative to each other:
588
+ ### Queues and Partitions
589
+
590
+ **Queues** are top-level organizational units. Each queue automatically gets a "Default" partition, and you can create additional partitions for logical separation or parallel processing.
268
591
 
269
592
  ```javascript
270
- // These can be processed in any order relative to each other
271
- await client.push({
272
- items: [
273
- { queue: 'tasks', partition: 'user-123', payload: { data: 'A' } },
274
- { queue: 'tasks', partition: 'user-456', payload: { data: 'B' } }
275
- ]
276
- });
593
+ // Messages go to "Default" partition
594
+ await client.push('orders', { orderId: 123 });
595
+
596
+ // Push to specific partition
597
+ await client.push('orders/high-priority', { orderId: 456 });
598
+
599
+ // Take from specific partition
600
+ for await (const order of client.take('orders/high-priority')) {
601
+ await processUrgentOrder(order.data);
602
+ await client.ack(order);
603
+ }
277
604
  ```
278
605
 
279
- #### Use Cases for Partitioning
606
+ **Partitions enable:**
607
+ - **Parallel processing**: Different consumers can process different partitions simultaneously
608
+ - **Ordered processing**: FIFO guarantees within each partition
609
+ - **Logical separation**: Different priorities, teams, or workflow stages
610
+ - **Resource isolation**: Lock contention is per-partition
280
611
 
281
- - **Per-User Processing**: Use user ID as partition to ensure all user operations are processed in order
282
- - **Per-Resource Processing**: Use resource ID to maintain operation order for specific resources
283
- - **Priority Lanes**: Use different partitions for different priority levels
612
+ ### Message Lifecycle
284
613
 
285
- ### Consumer Groups (Bus Mode)
614
+ ```
615
+ pending → processing → completed/failed → (retry) → dead_letter
616
+ ```
286
617
 
287
- Consumer groups enable pub-sub messaging patterns where multiple independent consumers can process the same messages. This is ideal for scenarios like event streaming, audit logging, and analytics.
618
+ 1. **Pending**: Message queued, waiting to be processed
619
+ 2. **Processing**: Leased to a worker (with timeout)
620
+ 3. **Completed**: Successfully processed
621
+ 4. **Failed**: Processing failed (may retry based on `retryLimit`)
622
+ 5. **Dead Letter**: Exceeded retry limits
288
623
 
289
- #### How Consumer Groups Work
624
+ ### Partition Locking
290
625
 
291
- 1. **Independent Processing**: Each consumer group maintains its own:
292
- - Message status tracking
293
- - Partition leases
294
- - Retry counters
295
- - Processing state
626
+ **Partition locking ensures message processing isolation** - when a consumer retrieves messages from a partition, that partition is locked to prevent other consumers from accessing it until:
296
627
 
297
- 2. **Message Visibility**: All consumer groups see all messages, but each group tracks which messages it has processed independently
628
+ - The consumer acknowledges all messages (releases lock)
629
+ - The lease expires (automatic release)
630
+ - The consumer explicitly releases the partition
298
631
 
299
- 3. **Partition Locking per Group**: Within a consumer group, partition locking still applies to prevent duplicate processing
632
+ **Lock Scope:**
633
+ - **Queue Mode**: Each consumer session is unique - locks prevent any other consumer from accessing the partition
634
+ - **Bus Mode**: Locks are per consumer group - different groups can process the same partition independently
300
635
 
301
636
  ```javascript
302
- // Analytics service (Group A)
303
- const analyticsResult = await client.pop({
304
- queue: 'events',
305
- consumerGroup: 'analytics-service'
306
- });
637
+ // Example: Partition locking in action
307
638
 
308
- // Audit service (Group B) - gets the same messages
309
- const auditResult = await client.pop({
310
- queue: 'events',
311
- consumerGroup: 'audit-service'
312
- });
639
+ // Consumer 1 takes from partition A (locks it)
640
+ for await (const msg of client.take('orders', { limit: 5 })) {
641
+ // Processing partition A - no other consumer can access it
642
+ await client.ack(msg);
643
+ // Partition A unlocked after all 5 messages acknowledged
644
+ }
313
645
 
314
- // Billing service (Group C) - also gets the same messages
315
- const billingResult = await client.pop({
316
- queue: 'events',
317
- consumerGroup: 'billing-service'
318
- });
646
+ // Consumer 2 gets messages from partition B (A was locked)
647
+ for await (const msg of client.take('orders', { limit: 5 })) {
648
+ // Processing partition B instead
649
+ await client.ack(msg);
650
+ }
319
651
  ```
320
652
 
321
- #### Consumer Group Subscription Modes
653
+ ### FIFO Ordering
322
654
 
323
- When a consumer group is created, it can specify when to start consuming messages:
655
+ Queen provides **strong FIFO guarantees within each partition**:
324
656
 
325
657
  ```javascript
326
- // Start from all existing messages
327
- await client.pop({
328
- queue: 'events',
329
- consumerGroup: 'replay-service',
330
- subscriptionMode: 'all'
331
- });
332
-
333
- // Start from messages created after joining
334
- await client.pop({
335
- queue: 'events',
336
- consumerGroup: 'realtime-service',
337
- subscriptionMode: 'new'
338
- });
658
+ // These messages will be processed in order 1, 2, 3
659
+ await client.push('tasks/user-123', [
660
+ { step: 1, action: 'create' },
661
+ { step: 2, action: 'update' },
662
+ { step: 3, action: 'complete' }
663
+ ]);
339
664
 
340
- // Start from a specific timestamp
341
- await client.pop({
342
- queue: 'events',
343
- consumerGroup: 'batch-processor',
344
- subscriptionFrom: '2024-01-01T00:00:00Z'
345
- });
665
+ // Consumer will always receive them in order
666
+ for await (const task of client.take('tasks/user-123')) {
667
+ console.log(task.data.step); // Prints: 1, then 2, then 3
668
+ await client.ack(task);
669
+ }
346
670
  ```
347
671
 
348
- ### Namespace and Task Filtering
672
+ **Use cases:**
673
+ - **Per-user operations**: Use user ID as partition for ordered processing
674
+ - **Per-resource operations**: Use resource ID to maintain operation order
675
+ - **Workflow stages**: Use partition to represent different stages
349
676
 
350
- Queen supports cross-queue message consumption through namespace and task filtering, with full partition locking support:
351
-
352
- #### Namespace-Based Routing
677
+ ### Consumer Groups (Bus Mode)
353
678
 
354
- Group related queues under a namespace and consume from all of them:
679
+ Consumer groups enable **pub-sub messaging** where multiple independent consumers process the same messages:
355
680
 
356
681
  ```javascript
357
- // Configure multiple queues with the same namespace
358
- await client.configure({
359
- queue: 'orders-processing',
360
- namespace: 'ecommerce',
361
- task: 'process',
362
- options: { leaseTime: 30 }
363
- });
682
+ // Push once
683
+ await client.push('events', { type: 'order.created', orderId: 123 });
684
+
685
+ // Multiple services consume independently
686
+ // Service 1: Analytics
687
+ for await (const event of client.take('events@analytics')) {
688
+ await updateAnalytics(event.data);
689
+ await client.ack(event);
690
+ }
364
691
 
365
- await client.configure({
366
- queue: 'inventory-updates',
367
- namespace: 'ecommerce',
368
- task: 'update',
369
- options: { leaseTime: 30 }
370
- });
692
+ // Service 2: Notification (gets same message)
693
+ for await (const event of client.take('events@notification')) {
694
+ await sendNotification(event.data);
695
+ await client.ack(event);
696
+ }
371
697
 
372
- // Consume from all queues in the namespace
373
- const messages = await client.pop({
374
- namespace: 'ecommerce'
375
- }, { batch: 10 });
376
- // Gets messages from both queues, with partition locking across all
698
+ // Service 3: Audit (also gets same message)
699
+ for await (const event of client.take('events@audit')) {
700
+ await logEvent(event.data);
701
+ await client.ack(event);
702
+ }
377
703
  ```
378
704
 
379
- #### Task-Based Routing
705
+ **Each consumer group maintains:**
706
+ - Independent message status tracking
707
+ - Separate partition leases
708
+ - Individual retry counters
709
+ - Isolated processing state
380
710
 
381
- Filter messages by specific tasks across namespaces:
711
+ ### Queue Mode vs Bus Mode
382
712
 
713
+ **Queue Mode** (default - competitive consumption):
383
714
  ```javascript
384
- // Consume only 'process' tasks from the ecommerce namespace
385
- const messages = await client.pop({
386
- namespace: 'ecommerce',
387
- task: 'process'
388
- }, { batch: 5 });
389
- ```
715
+ // Without consumer group - messages distributed
716
+ await client.push('tasks', { id: 1 });
717
+ await client.push('tasks', { id: 2 });
390
718
 
391
- #### Partition Locking with Filters
719
+ // Worker 1 gets message 1
720
+ for await (const msg of client.take('tasks')) { }
392
721
 
393
- When using namespace/task filtering:
394
- - The system locks all partitions from which messages are retrieved
395
- - Different consumers cannot access the same partitions until locks are released
396
- - Consumer groups maintain independent locks
722
+ // Worker 2 gets message 2 (different message)
723
+ for await (const msg of client.take('tasks')) { }
724
+ ```
397
725
 
726
+ **Bus Mode** (pub-sub with consumer groups):
398
727
  ```javascript
399
- // Consumer 1: Gets messages and locks partitions A, B, C
400
- const result1 = await client.pop({ namespace: 'ecommerce' });
728
+ // With consumer groups - all groups see all messages
729
+ await client.push('events', { id: 1 });
401
730
 
402
- // Consumer 2: Gets messages from different partitions D, E (A, B, C are locked)
403
- const result2 = await client.pop({ namespace: 'ecommerce' });
731
+ // Group 1 gets message 1
732
+ for await (const msg of client.take('events@group1')) { }
404
733
 
405
- // No partition overlap between consumers
734
+ // Group 2 also gets message 1 (same message)
735
+ for await (const msg of client.take('events@group2')) { }
406
736
  ```
407
737
 
408
- ### Concurrency Control
738
+ **Mixed Mode** (combine both):
739
+ ```javascript
740
+ // Competitive workers process jobs
741
+ for await (const job of client.take('jobs')) {
742
+ await processJob(job.data);
743
+ await client.ack(job);
744
+ }
409
745
 
410
- Queen provides several mechanisms for controlling concurrent message processing:
746
+ // Monitoring sees all jobs (bus mode)
747
+ for await (const job of client.take('jobs@monitoring')) {
748
+ await monitorJob(job.data);
749
+ await client.ack(job);
750
+ }
751
+ ```
411
752
 
412
- #### 1. Partition-Based Concurrency
753
+ ### Priority Processing
413
754
 
414
- Control parallelism by the number of partitions:
755
+ Configure priority at the **queue level**:
415
756
 
416
757
  ```javascript
417
- // Create multiple partitions for parallel processing
418
- const partitions = ['worker-1', 'worker-2', 'worker-3', 'worker-4'];
758
+ await client.queue('urgent-orders', { priority: 100 });
759
+ await client.queue('normal-orders', { priority: 50 });
760
+ await client.queue('batch-jobs', { priority: 10 });
419
761
 
420
- // Distribute messages across partitions
421
- await client.push({
422
- items: messages.map((msg, i) => ({
423
- queue: 'tasks',
424
- partition: partitions[i % partitions.length],
425
- payload: msg
426
- }))
762
+ // Urgent orders processed first, then normal, then batch
763
+ ```
764
+
765
+ ### Lease-Based Processing
766
+
767
+ Messages are "leased" to workers for a specific duration. If not acknowledged within the lease time, they automatically return to pending status:
768
+
769
+ ```javascript
770
+ // Configure lease time
771
+ await client.queue('long-tasks', {
772
+ leaseTime: 600 // 10 minutes to process
427
773
  });
428
774
 
429
- // Each worker processes one partition
430
- const worker1 = await client.pop({ queue: 'tasks', partition: 'worker-1' });
431
- const worker2 = await client.pop({ queue: 'tasks', partition: 'worker-2' });
432
- // Workers process in parallel without interference
775
+ // If worker crashes or takes too long:
776
+ // - After 10 minutes, lease expires
777
+ // - Message returns to pending
778
+ // - Another worker can pick it up
433
779
  ```
434
780
 
435
- #### 2. Lease-Based Concurrency
781
+ ### Delayed Processing
436
782
 
437
- Automatic concurrency control through lease timeouts:
783
+ Schedule messages for future processing:
438
784
 
439
785
  ```javascript
440
- // Configure short leases for quick tasks
441
- await client.configure({
442
- queue: 'quick-tasks',
443
- options: {
444
- leaseTime: 30, // 30 seconds per message
445
- retryLimit: 3 // Retry up to 3 times
446
- }
786
+ await client.queue('scheduled-jobs', {
787
+ delayedProcessing: 3600 // 1 hour delay
447
788
  });
448
789
 
449
- // Long-running tasks need longer leases
450
- await client.configure({
451
- queue: 'heavy-processing',
452
- options: {
453
- leaseTime: 600, // 10 minutes per message
454
- retryLimit: 1 // Retry only once
455
- }
790
+ await client.push('scheduled-jobs', {
791
+ reportType: 'daily-sales'
456
792
  });
793
+ // Message won't be available for processing until 1 hour later
457
794
  ```
458
795
 
459
- #### 3. Batch Size Control
796
+ ### Window Buffering
460
797
 
461
- Limit concurrent processing per consumer:
798
+ Batch messages within a time window:
462
799
 
463
800
  ```javascript
464
- // Each consumer processes max 5 messages at a time
465
- const batch = await client.pop({
466
- queue: 'tasks'
467
- }, {
468
- batch: 5 // Limit to 5 concurrent messages
801
+ await client.queue('analytics', {
802
+ windowBuffer: 60 // Wait 60 seconds to accumulate messages
469
803
  });
470
804
 
471
- // Process batch
472
- for (const message of batch.messages) {
473
- await processMessage(message);
474
- await client.ack(message.transactionId, 'completed');
475
- }
805
+ // Messages held for 60 seconds to allow efficient batching
476
806
  ```
477
807
 
478
- ### Message Visibility and Isolation
808
+ ### Retry and Dead Letter Queue
479
809
 
480
- #### Queue Mode (Default)
810
+ ```javascript
811
+ await client.queue('payments', {
812
+ retryLimit: 3, // Retry up to 3 times
813
+ dlqAfterMaxRetries: true // Move to DLQ after max retries
814
+ });
481
815
 
482
- In queue mode, messages are consumed competitively - once a consumer gets a message, no other consumer can see it:
816
+ // Failed messages automatically retry
817
+ await client.ack(message, false); // Will retry if retries < 3
483
818
 
484
- ```javascript
485
- // Without consumer group - competitive consumption
486
- const consumer1 = await client.pop({ queue: 'tasks' });
487
- const consumer2 = await client.pop({ queue: 'tasks' });
488
- // Each consumer gets different messages
819
+ // After 3 failures, message moves to dead_letter status
489
820
  ```
490
821
 
491
- #### Bus Mode (Consumer Groups)
822
+ ### Enterprise Features
823
+
824
+ #### 1. Encryption (AES-256-GCM)
492
825
 
493
- In bus mode, all consumer groups see all messages:
826
+ ```bash
827
+ # Generate encryption key
828
+ export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
829
+ ```
494
830
 
495
831
  ```javascript
496
- // With consumer groups - broadcast consumption
497
- const service1 = await client.pop({
498
- queue: 'events',
499
- consumerGroup: 'service-1'
832
+ await client.queue('sensitive-data', {
833
+ encryptionEnabled: true
500
834
  });
501
835
 
502
- const service2 = await client.pop({
503
- queue: 'events',
504
- consumerGroup: 'service-2'
505
- });
506
- // Both services get the same messages
836
+ // Messages encrypted at rest in database
837
+ await client.push('sensitive-data', { ssn: '123-45-6789' });
507
838
  ```
508
839
 
509
- #### Mixed Mode
510
-
511
- You can combine both patterns in the same system:
840
+ #### 2. Message Retention
512
841
 
513
842
  ```javascript
514
- // Competitive workers for processing
515
- const worker = await client.pop({ queue: 'jobs' });
516
-
517
- // Broadcast to monitoring services
518
- const monitor = await client.pop({
519
- queue: 'jobs',
520
- consumerGroup: 'monitoring'
843
+ await client.queue('temp-queue', {
844
+ retentionSeconds: 3600, // Delete pending after 1 hour
845
+ completedRetentionSeconds: 300, // Delete completed after 5 minutes
846
+ retentionEnabled: true
521
847
  });
848
+ ```
849
+
850
+ #### 3. Message Eviction (SLA Enforcement)
522
851
 
523
- const analytics = await client.pop({
524
- queue: 'jobs',
525
- consumerGroup: 'analytics'
852
+ ```javascript
853
+ await client.queue('time-sensitive', {
854
+ maxWaitTimeSeconds: 60 // Evict messages older than 1 minute
526
855
  });
527
856
  ```
528
857
 
529
858
  ### Best Practices
530
859
 
531
- #### 1. Partition Strategy
860
+ **1. Partition Strategy**
861
+ - Use user IDs for per-user ordering
862
+ - Use resource IDs for per-resource ordering
863
+ - Use round-robin for load distribution
864
+ - Keep partition counts manageable (10-100s, not 1000s)
532
865
 
533
- - **User-based**: Use user IDs as partitions for per-user ordering
534
- - **Resource-based**: Use resource IDs for ordered operations on resources
535
- - **Round-robin**: Use rotating partition names for load distribution
536
- - **Priority-based**: Use separate partitions for different priority levels
866
+ **2. Lease Management**
867
+ - Set lease time slightly longer than expected processing time
868
+ - Handle timeouts gracefully
869
+ - Acknowledge messages as soon as processing completes
537
870
 
538
- #### 2. Consumer Group Design
871
+ **3. Consumer Group Design**
872
+ - One clear purpose per consumer group
873
+ - Design groups to be independent
874
+ - Ensure operations are idempotent
539
875
 
540
- - **Single Responsibility**: Each consumer group should have one clear purpose
541
- - **Independent Processing**: Design groups to be independent of each other
542
- - **Idempotent Operations**: Ensure operations can be safely retried
876
+ **4. Error Handling**
877
+ - Always wrap processing in try-catch
878
+ - Provide meaningful error messages in ack
879
+ - Use retry limits appropriately
880
+ - Monitor dead letter queue
543
881
 
544
- #### 3. Lease Management
882
+ ---
545
883
 
546
- - **Right-size Leases**: Set lease times slightly longer than expected processing time
547
- - **Handle Timeouts**: Implement proper timeout handling and retries
548
- - **Release Early**: Acknowledge messages as soon as processing completes
884
+ ## 🔌 HTTP API Reference
549
885
 
550
- #### 4. Error Handling
551
-
552
- ```javascript
553
- try {
554
- const messages = await client.pop({ queue: 'tasks' });
555
-
556
- for (const message of messages.messages) {
557
- try {
558
- await processMessage(message);
559
- await client.ack(message.transactionId, 'completed');
560
- } catch (error) {
561
- // Log error but don't ack - message will retry
562
- console.error('Processing failed:', error);
563
- await client.ack(message.transactionId, 'failed', error.message);
564
- }
565
- }
566
- } catch (error) {
567
- console.error('Pop failed:', error);
568
- }
569
- ```
570
-
571
- ## 🔌 API Reference
572
-
573
- ### Base URL
574
- ```
575
- http://localhost:6632/api/v1
576
- ```
886
+ Base URL: `http://localhost:6632/api/v1`
577
887
 
578
888
  ### Push Messages
579
889
 
580
890
  **Endpoint:** `POST /api/v1/push`
581
891
 
582
- ```javascript
892
+ **Request:**
893
+ ```json
583
894
  {
584
895
  "items": [
585
896
  {
586
- "queue": "email-queue", // Required
587
- "partition": "urgent", // Optional (defaults to "Default")
588
- "payload": { // Required: message data
589
- "to": "user@example.com",
590
- "subject": "Hello"
591
- },
592
- "transactionId": "uuid-here" // Optional: for idempotency
897
+ "queue": "orders",
898
+ "partition": "urgent",
899
+ "payload": { "orderId": 123, "amount": 99.99 },
900
+ "transactionId": "optional-idempotency-key",
901
+ "traceId": "550e8400-e29b-41d4-a716-446655440000"
593
902
  }
594
903
  ]
595
904
  }
596
905
  ```
597
906
 
598
907
  **Response:**
599
- ```javascript
908
+ ```json
600
909
  {
601
910
  "messages": [
602
911
  {
@@ -610,35 +919,40 @@ http://localhost:6632/api/v1
610
919
 
611
920
  ### Pop Messages
612
921
 
613
- **From Specific Partition:**
922
+ **From specific partition:**
614
923
  ```
615
924
  GET /api/v1/pop/queue/{queue}/partition/{partition}?wait=true&timeout=30000&batch=10
616
925
  ```
617
926
 
618
- **From Any Partition in Queue:**
927
+ **From any partition in queue:**
619
928
  ```
620
929
  GET /api/v1/pop/queue/{queue}?wait=true&timeout=30000&batch=10
621
930
  ```
622
931
 
623
- **With Namespace/Task Filter:**
932
+ **With namespace/task filter:**
933
+ ```
934
+ GET /api/v1/pop?namespace=ecommerce&task=checkout&wait=true&timeout=30000&batch=10
935
+ ```
936
+
937
+ **With consumer group (bus mode):**
624
938
  ```
625
- GET /api/v1/pop?namespace=my-app&task=emails&wait=true&timeout=30000&batch=10
939
+ GET /api/v1/pop/queue/{queue}?consumerGroup=analytics&subscriptionMode=all&wait=true&timeout=30000
626
940
  ```
627
941
 
628
942
  **Response:**
629
- ```javascript
943
+ ```json
630
944
  {
631
945
  "messages": [
632
946
  {
633
947
  "id": "018e63b7-6165-453f-88ae-56effa177605",
634
948
  "transactionId": "4dfb0478-655b-4c91-bcd9-b7acacf0400f",
635
- "queue": "email-queue",
949
+ "queue": "orders",
636
950
  "partition": "urgent",
637
- "data": { "to": "user@example.com", "subject": "Hello" },
951
+ "data": { "orderId": 123, "amount": 99.99 },
638
952
  "retryCount": 0,
639
953
  "priority": 10,
640
- "createdAt": "2023-10-08T12:00:00.000Z",
641
- "options": { "leaseTime": 300 }
954
+ "createdAt": "2024-10-08T12:00:00.000Z",
955
+ "options": { "leaseTime": 300, "retryLimit": 3 }
642
956
  }
643
957
  ]
644
958
  }
@@ -646,850 +960,967 @@ GET /api/v1/pop?namespace=my-app&task=emails&wait=true&timeout=30000&batch=10
646
960
 
647
961
  ### Acknowledge Messages
648
962
 
649
- **Single Acknowledgment:**
650
- ```javascript
963
+ **Single:**
964
+ ```json
651
965
  POST /api/v1/ack
652
966
  {
653
- "transactionId": "uuid",
654
- "status": "completed", // "completed" or "failed"
655
- "error": "optional error" // Required if status is "failed"
967
+ "transactionId": "4dfb0478-655b-4c91-bcd9-b7acacf0400f",
968
+ "status": "completed",
969
+ "consumerGroup": "analytics",
970
+ "error": null
656
971
  }
657
972
  ```
658
973
 
659
- **Batch Acknowledgment:**
660
- ```javascript
974
+ **Batch:**
975
+ ```json
661
976
  POST /api/v1/ack/batch
662
977
  {
663
978
  "acknowledgments": [
664
- { "transactionId": "uuid1", "status": "completed" },
665
- { "transactionId": "uuid2", "status": "failed", "error": "Processing error" }
979
+ { "transactionId": "uuid-1", "status": "completed" },
980
+ { "transactionId": "uuid-2", "status": "failed", "error": "Processing error" }
666
981
  ]
667
982
  }
668
983
  ```
669
984
 
670
- ### Queue Configuration
985
+ ### Configure Queue
671
986
 
672
- ```javascript
987
+ ```json
673
988
  POST /api/v1/configure
674
989
  {
675
- "queue": "email-queue",
676
- "partition": "urgent", // Optional (defaults to "Default")
990
+ "queue": "orders",
991
+ "namespace": "ecommerce",
992
+ "task": "checkout",
677
993
  "options": {
678
- "leaseTime": 600, // Seconds before lease expires
679
- "retryLimit": 5, // Max retry attempts
680
- "priority": 10, // Partition priority (higher = first)
681
- "delayedProcessing": 60, // Delay before message becomes available
682
- "windowBuffer": 30 // Buffer messages for batch processing
994
+ "leaseTime": 600,
995
+ "retryLimit": 5,
996
+ "priority": 10,
997
+ "maxSize": 10000,
998
+ "ttl": 3600,
999
+ "dlqAfterMaxRetries": true,
1000
+ "delayedProcessing": 0,
1001
+ "windowBuffer": 0,
1002
+ "retentionSeconds": 0,
1003
+ "completedRetentionSeconds": 0,
1004
+ "retentionEnabled": false,
1005
+ "encryptionEnabled": false,
1006
+ "maxWaitTimeSeconds": 0
683
1007
  }
684
1008
  }
685
1009
  ```
686
1010
 
687
1011
  ### Analytics
688
1012
 
689
- ```javascript
690
- // Get all queues overview
691
- GET /api/v1/analytics/queues
1013
+ **Queue statistics:**
1014
+ ```
1015
+ GET /api/v1/analytics/queue/{queue}
1016
+ ```
692
1017
 
693
- // Get queue statistics
694
- GET /api/v1/analytics/queue/{queueName}
1018
+ **All queues overview:**
1019
+ ```
1020
+ GET /api/v1/analytics/queues
1021
+ ```
695
1022
 
696
- // Get namespace statistics
697
- GET /api/v1/analytics?namespace={namespace}
1023
+ **Queue depths:**
1024
+ ```
1025
+ GET /api/v1/analytics/queue-depths
1026
+ ```
698
1027
 
699
- // Get throughput metrics
1028
+ **Throughput metrics:**
1029
+ ```
700
1030
  GET /api/v1/analytics/throughput
1031
+ ```
701
1032
 
702
- // Get queue depths
703
- GET /api/v1/analytics/queue-depths
1033
+ **Queue lag analysis:**
1034
+ ```
1035
+ GET /api/v1/analytics/queue-lag?queue=orders
704
1036
  ```
705
1037
 
706
- ## 📱 Client SDK
1038
+ ### Message Management
707
1039
 
708
- ### Installation
1040
+ **List messages:**
1041
+ ```
1042
+ GET /api/v1/messages?queue=orders&status=pending&limit=100
1043
+ ```
709
1044
 
710
- ```javascript
711
- import { createQueenClient } from './src/client/queenClient.js';
1045
+ **Get single message:**
1046
+ ```
1047
+ GET /api/v1/messages/{transactionId}
1048
+ ```
712
1049
 
713
- const client = createQueenClient({
714
- baseUrl: 'http://localhost:6632',
715
- timeout: 30000,
716
- retryAttempts: 3,
717
- retryDelay: 1000
718
- });
1050
+ **Delete message:**
1051
+ ```
1052
+ DELETE /api/v1/messages/{transactionId}
719
1053
  ```
720
1054
 
721
- ### Basic Operations
1055
+ **Retry failed message:**
1056
+ ```
1057
+ POST /api/v1/messages/{transactionId}/retry
1058
+ ```
722
1059
 
723
- ```javascript
724
- // Configure a queue
725
- await client.configure({
726
- queue: 'orders',
727
- options: {
728
- priority: 10,
729
- leaseTime: 600,
730
- retryLimit: 3
731
- }
732
- });
1060
+ **Move to dead letter queue:**
1061
+ ```
1062
+ POST /api/v1/messages/{transactionId}/dlq
1063
+ ```
733
1064
 
734
- // Push single message
735
- await client.push({
736
- items: [{
737
- queue: 'orders',
738
- partition: 'high-priority',
739
- payload: { orderId: 123, amount: 99.99 }
740
- }]
741
- });
1065
+ **Clear queue:**
1066
+ ```
1067
+ DELETE /api/v1/queues/{queue}/clear
1068
+ ```
742
1069
 
743
- // Push batch of messages
744
- await client.push({
745
- items: [
746
- { queue: 'orders', payload: { orderId: 124 } },
747
- { queue: 'orders', payload: { orderId: 125 } },
748
- { queue: 'orders', payload: { orderId: 126 } }
749
- ]
750
- });
1070
+ ### System Health
751
1071
 
752
- // Pop messages with long polling
753
- const result = await client.pop({
754
- queue: 'orders',
755
- wait: true,
756
- timeout: 30000,
757
- batch: 10
758
- });
1072
+ **Health check:**
1073
+ ```
1074
+ GET /health
1075
+ ```
759
1076
 
760
- // Process messages
761
- for (const message of result.messages) {
762
- try {
763
- await processOrder(message.data);
764
- await client.ack(message.transactionId, 'completed');
765
- } catch (error) {
766
- await client.ack(message.transactionId, 'failed', error.message);
767
- }
768
- }
1077
+ **Detailed metrics:**
1078
+ ```
1079
+ GET /metrics
769
1080
  ```
770
1081
 
771
- ### Consumer Pattern
1082
+ ### WebSocket (Real-time Updates)
772
1083
 
773
- The SDK provides a convenient consumer helper for continuous message processing with two modes:
1084
+ **Connect:**
1085
+ ```javascript
1086
+ const ws = new WebSocket('ws://localhost:6632/ws/dashboard');
774
1087
 
775
- #### Individual Message Processing
1088
+ ws.onmessage = (event) => {
1089
+ const { event: eventType, data } = JSON.parse(event.data);
1090
+ // Handle events: message.pushed, message.completed, queue.depth, etc.
1091
+ };
1092
+ ```
776
1093
 
777
- Process messages one by one (default behavior):
1094
+ **Events:**
1095
+ - `message.pushed` - New message added
1096
+ - `message.processing` - Message being processed
1097
+ - `message.completed` - Message completed
1098
+ - `message.failed` - Message failed
1099
+ - `queue.created` - New queue created
1100
+ - `queue.depth` - Queue depth update (every 5s)
1101
+ - `system.stats` - System statistics (every 10s)
778
1102
 
779
- ```javascript
780
- const stopConsumer = client.consume({
781
- queue: 'orders',
782
- partition: 'high-priority',
783
- handler: async (message) => {
784
- console.log('Processing order:', message.data.orderId);
785
- await processOrder(message.data);
786
- // Message is automatically acknowledged on success
787
- },
788
- options: {
789
- batch: 5,
790
- wait: true,
791
- timeout: 30000,
792
- stopOnError: false
793
- }
794
- });
1103
+ See [API.md](API.md) for complete API documentation.
795
1104
 
796
- // Stop the consumer when needed
797
- // stopConsumer();
798
- ```
1105
+ ---
799
1106
 
800
- #### Batch Message Processing
1107
+ ## 📊 Dashboard
801
1108
 
802
- Process entire batches of messages at once for better performance:
1109
+ Queen includes a comprehensive web dashboard for monitoring and management.
803
1110
 
804
- ```javascript
805
- const stopConsumer = client.consume({
806
- queue: 'orders',
807
- partition: 'high-priority',
808
- handlerBatch: async (messages) => {
809
- console.log(`Processing batch of ${messages.length} orders`);
810
-
811
- // Process all messages in parallel
812
- await Promise.all(messages.map(async (message) => {
813
- console.log('Processing order:', message.data.orderId);
814
- await processOrder(message.data);
815
- }));
816
-
817
- // Or process sequentially if needed
818
- // for (const message of messages) {
819
- // await processOrder(message.data);
820
- // }
821
-
822
- // All messages are automatically batch-acknowledged on success
823
- },
824
- options: {
825
- batch: 10, // Larger batches for better throughput
826
- wait: true,
827
- timeout: 30000,
828
- stopOnError: false
829
- }
830
- });
1111
+ ### Access
1112
+
1113
+ 1. Start the server: `npm start`
1114
+ 2. Open browser: `http://localhost:6632`
1115
+ 3. WebSocket connection provides real-time updates
1116
+
1117
+ ### Features
1118
+
1119
+ **System Overview**
1120
+ - Real-time metrics: total messages, processing rate, system health
1121
+ - Queue summary with pending/processing/completed counts
1122
+ - Performance indicators: throughput, latency, error rates
1123
+
1124
+ **Queue Management**
1125
+ - Queue list with status and message counts
1126
+ - Partition view with priority indicators
1127
+ - Message browser with search and filter
1128
+ - Retry and DLQ management
1129
+
1130
+ **Real-time Monitoring**
1131
+ - Live updates via WebSocket
1132
+ - Throughput charts (messages per second over time)
1133
+ - Queue depth graphs with trend analysis
1134
+ - Lag monitoring (processing time and backlog)
1135
+
1136
+ **Analytics Dashboard**
1137
+ - Performance metrics per queue
1138
+ - Historical trends and patterns
1139
+ - System health monitoring
1140
+ - Database connections and memory usage
1141
+
1142
+ **Message Browser**
1143
+ - Search by queue, partition, status, time range
1144
+ - View full payload and metadata
1145
+ - Manually retry failed messages
1146
+ - Dead letter queue management
1147
+
1148
+ ### Dashboard Development
1149
+
1150
+ The dashboard is built with Vue.js and located in the `dashboard/` directory:
1151
+
1152
+ ```bash
1153
+ cd dashboard
1154
+ npm install
1155
+ npm run dev # Development mode
1156
+ npm run build # Production build
831
1157
  ```
832
1158
 
833
- **Key Benefits of Batch Processing:**
834
- - **Higher Throughput**: Process multiple messages simultaneously
835
- - **Efficient Acknowledgments**: Single batch ACK instead of individual ACKs
836
- - **Atomic Processing**: Either the entire batch succeeds or fails together
837
- - **Reduced Network Overhead**: Fewer round trips to the server
1159
+ ---
838
1160
 
839
- **Important Notes:**
840
- - Use either `handler` OR `handlerBatch`, not both
841
- - In batch mode, if processing fails, all messages in the batch are marked as failed
842
- - Batch size is controlled by the `batch` option (default: 1)
1161
+ ## ⚙️ Configuration
843
1162
 
844
- ### Advanced Features
1163
+ All configuration uses environment variables with sensible defaults. Configuration is centralized in `src/config.js`.
845
1164
 
846
- ```javascript
847
- // Pop with namespace filter (cross-queue priority)
848
- const result = await client.pop({
849
- namespace: 'ecommerce',
850
- batch: 10,
851
- wait: true
852
- });
1165
+ ### Server Configuration
853
1166
 
854
- // Batch acknowledgment
855
- await client.ackBatch([
856
- { transactionId: 'uuid1', status: 'completed' },
857
- { transactionId: 'uuid2', status: 'failed', error: 'Invalid data' }
858
- ]);
1167
+ ```bash
1168
+ PORT=6632 # Server port (default: 6632)
1169
+ HOST=0.0.0.0 # Server host (default: 0.0.0.0)
1170
+ WORKER_ID=worker-1 # Worker identifier
1171
+ APP_NAME=queen-mq # Application name
859
1172
 
860
- // Message management
861
- const messages = await client.messages.list({
862
- queue: 'orders',
863
- status: 'failed',
864
- limit: 100
865
- });
1173
+ # CORS
1174
+ CORS_MAX_AGE=86400
1175
+ CORS_ALLOWED_ORIGINS=*
1176
+ CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,OPTIONS
1177
+ CORS_ALLOWED_HEADERS=Content-Type,Authorization
1178
+ ```
1179
+
1180
+ ### Database Configuration
1181
+
1182
+ ```bash
1183
+ # Connection
1184
+ PG_USER=postgres
1185
+ PG_HOST=localhost
1186
+ PG_DB=postgres
1187
+ PG_PASSWORD=postgres
1188
+ PG_PORT=5432
866
1189
 
867
- await client.messages.retry('transaction-id');
868
- await client.messages.moveToDLQ('transaction-id');
1190
+ # Connection pool
1191
+ DB_POOL_SIZE=20 # Max connections
1192
+ DB_IDLE_TIMEOUT=30000 # Idle timeout (ms)
1193
+ DB_CONNECTION_TIMEOUT=2000 # Connection timeout (ms)
1194
+ DB_STATEMENT_TIMEOUT=30000 # Statement timeout (ms)
1195
+ DB_QUERY_TIMEOUT=30000 # Query timeout (ms)
1196
+ DB_MAX_RETRIES=3 # Max retry attempts
869
1197
  ```
870
1198
 
871
- ## 📊 Dashboard
1199
+ ### Queue Processing
872
1200
 
873
- The Queen system includes a comprehensive web dashboard for monitoring and management.
874
-
875
- ### Accessing the Dashboard
876
-
877
- 1. **Start the server**: `npm start`
878
- 2. **Open dashboard**: Navigate to `http://localhost:6632` in your browser
879
- 3. **WebSocket connection**: The dashboard connects via WebSocket for real-time updates
880
-
881
- ### Dashboard Features
882
-
883
- #### 1. **System Overview**
884
- - **Real-time Metrics**: Total messages, processing rate, system health
885
- - **Queue Summary**: Active queues, pending messages, processing status
886
- - **Performance Indicators**: Throughput, latency, error rates
887
-
888
- #### 2. **Queue Management**
889
- - **Queue List**: All queues with current status and message counts
890
- - **Partition View**: Partitions within each queue with priority indicators
891
- - **Message Counts**: Pending, processing, completed, failed, and dead letter counts
892
- - **Priority Visualization**: Color-coded priority levels
893
-
894
- #### 3. **Real-time Monitoring**
895
- - **Live Updates**: WebSocket-powered real-time data updates
896
- - **Throughput Charts**: Messages per second over time
897
- - **Queue Depth Graphs**: Pending message counts with trend analysis
898
- - **Lag Monitoring**: Processing time and queue lag metrics
899
-
900
- #### 4. **Message Browser**
901
- - **Message Search**: Filter by queue, partition, status, or time range
902
- - **Message Details**: Full payload, metadata, and processing history
903
- - **Retry Management**: Manually retry failed messages
904
- - **Dead Letter Queue**: View and manage messages that exceeded retry limits
905
-
906
- #### 5. **Analytics Dashboard**
907
- - **Performance Metrics**: Detailed throughput and latency statistics
908
- - **Queue Analytics**: Per-queue performance and usage patterns
909
- - **Historical Data**: Trends and patterns over time
910
- - **System Health**: Database connections, memory usage, error rates
911
-
912
- #### 6. **Configuration Management**
913
- - **Queue Configuration**: View and modify queue settings
914
- - **Partition Settings**: Priority, lease time, retry limits
915
- - **System Settings**: Global configuration options
916
-
917
- ### Dashboard Components
918
-
919
- The dashboard is built with Vue.js and includes:
920
-
921
- ```
922
- dashboard/
923
- ├── src/
924
- │ ├── components/
925
- │ │ ├── charts/ # Chart components
926
- │ │ │ ├── QueueDepthChart.vue
927
- │ │ │ ├── QueueLagChart.vue
928
- │ │ │ └── ThroughputChart.vue
929
- │ │ ├── cards/ # Metric cards
930
- │ │ │ └── MetricCard.vue
931
- │ │ ├── common/ # Shared components
932
- │ │ │ └── ActivityFeed.vue
933
- │ │ └── layout/ # Layout components
934
- │ │ ├── AppHeader.vue
935
- │ │ ├── AppLayout.vue
936
- │ │ └── AppSidebar.vue
937
- │ ├── views/ # Main pages
938
- │ │ ├── Dashboard.vue # System overview
939
- │ │ ├── Queues.vue # Queue management
940
- │ │ ├── QueueDetail.vue # Individual queue details
941
- │ │ ├── Messages.vue # Message browser
942
- │ │ └── Analytics.vue # Analytics dashboard
943
- │ └── services/
944
- │ ├── api.js # API client
945
- │ └── websocket.js # WebSocket connection
946
- ```
947
-
948
- ### WebSocket API
949
-
950
- The dashboard connects via WebSocket for real-time updates:
1201
+ ```bash
1202
+ # Pop defaults
1203
+ DEFAULT_TIMEOUT=30000 # Default pop timeout (ms)
1204
+ MAX_TIMEOUT=60000 # Maximum pop timeout (ms)
1205
+ DEFAULT_BATCH_SIZE=1 # Default batch size
1206
+ BATCH_INSERT_SIZE=1000 # Batch size for bulk inserts
951
1207
 
952
- ```javascript
953
- // Connect to dashboard WebSocket
954
- const ws = new WebSocket('ws://localhost:6632/ws/dashboard');
1208
+ # Long polling
1209
+ QUEUE_POLL_INTERVAL=100 # Poll interval (ms)
1210
+ QUEUE_POLL_INTERVAL_FILTERED=1000 # Poll interval for filtered pops (ms)
955
1211
 
956
- // Receive real-time updates
957
- ws.onmessage = (event) => {
958
- const { event: eventType, data } = JSON.parse(event.data);
959
-
960
- switch (eventType) {
961
- case 'queue.depth.updated':
962
- updateQueueDepth(data);
963
- break;
964
- case 'message.processed':
965
- updateThroughput(data);
966
- break;
967
- case 'system.stats':
968
- updateSystemStats(data);
969
- break;
970
- }
971
- };
1212
+ # Queue defaults
1213
+ DEFAULT_LEASE_TIME=300 # Lease time (seconds)
1214
+ DEFAULT_RETRY_LIMIT=3 # Retry limit
1215
+ DEFAULT_RETRY_DELAY=1000 # Retry delay (ms)
1216
+ DEFAULT_MAX_SIZE=10000 # Max queue size
1217
+ DEFAULT_TTL=3600 # TTL (seconds)
1218
+ DEFAULT_PRIORITY=0 # Priority
1219
+ DEFAULT_DELAYED_PROCESSING=0 # Delayed processing (seconds)
1220
+ DEFAULT_WINDOW_BUFFER=0 # Window buffer (seconds)
972
1221
  ```
973
1222
 
974
- ## 📚 Examples
1223
+ ### Background Jobs
975
1224
 
976
- ### Basic Email Queue
1225
+ ```bash
1226
+ LEASE_RECLAIM_INTERVAL=5000 # Lease reclamation (ms)
1227
+ RETENTION_INTERVAL=300000 # Retention checks (ms)
1228
+ RETENTION_BATCH_SIZE=1000 # Retention batch size
1229
+ PARTITION_CLEANUP_DAYS=7 # Days before cleaning empty partitions
1230
+ EVICTION_INTERVAL=60000 # Eviction checks (ms)
1231
+ EVICTION_BATCH_SIZE=1000 # Eviction batch size
1232
+ ```
977
1233
 
978
- ```javascript
979
- // Configure email queue with priority
980
- await client.configure({
981
- queue: 'emails-urgent',
982
- options: { priority: 10, leaseTime: 300 }
983
- });
1234
+ ### WebSocket
984
1235
 
985
- await client.configure({
986
- queue: 'emails-normal',
987
- options: { priority: 5, leaseTime: 300 }
988
- });
1236
+ ```bash
1237
+ WS_COMPRESSION=0 # Compression level
1238
+ WS_MAX_PAYLOAD_LENGTH=16384 # Max payload (bytes)
1239
+ WS_IDLE_TIMEOUT=60 # Idle timeout (seconds)
1240
+ WS_MAX_CONNECTIONS=1000 # Max connections
1241
+ WS_HEARTBEAT_INTERVAL=30000 # Heartbeat (ms)
1242
+ ```
989
1243
 
990
- // Send urgent email
991
- await client.push({
992
- items: [{
993
- queue: 'emails',
994
- partition: 'urgent',
995
- payload: {
996
- to: 'admin@company.com',
997
- subject: 'System Alert',
998
- body: 'Critical system issue detected'
999
- }
1000
- }]
1001
- });
1244
+ ### Encryption
1002
1245
 
1003
- // Process emails (urgent emails processed first)
1004
- const result = await client.pop({
1005
- queue: 'emails',
1006
- batch: 10,
1007
- wait: true
1008
- });
1246
+ ```bash
1247
+ # Generate key: openssl rand -hex 32
1248
+ QUEEN_ENCRYPTION_KEY=<64-hex-chars> # AES-256-GCM encryption key
1009
1249
  ```
1010
1250
 
1011
- ### Delayed Job Processing
1251
+ ### Client SDK
1012
1252
 
1013
- ```javascript
1014
- // Configure queue with delayed processing
1015
- await client.configure({
1016
- queue: 'scheduled-jobs',
1017
- options: {
1018
- delayedProcessing: 3600, // 1 hour delay
1019
- priority: 5
1020
- }
1021
- });
1253
+ ```bash
1254
+ QUEEN_BASE_URL=http://localhost:6632
1255
+ CLIENT_RETRY_ATTEMPTS=3
1256
+ CLIENT_RETRY_DELAY=1000
1257
+ CLIENT_RETRY_BACKOFF=2
1258
+ CLIENT_POOL_SIZE=10
1259
+ CLIENT_REQUEST_TIMEOUT=30000
1260
+ ```
1022
1261
 
1023
- // Schedule a job for later processing
1024
- await client.push({
1025
- items: [{
1026
- queue: 'scheduled-jobs',
1027
- partition: 'daily-reports',
1028
- payload: {
1029
- reportType: 'daily-sales',
1030
- date: '2023-10-08',
1031
- recipients: ['manager@company.com']
1032
- }
1033
- }]
1034
- });
1262
+ ### Queue Options
1035
1263
 
1036
- // Job will not be available for processing until 1 hour later
1264
+ ```javascript
1265
+ {
1266
+ // Processing
1267
+ leaseTime: 300, // Seconds before lease expires
1268
+ retryLimit: 3, // Max retry attempts
1269
+ priority: 0, // Queue priority (higher = first)
1270
+ delayedProcessing: 0, // Delay in seconds
1271
+ windowBuffer: 0, // Buffer time for batching
1272
+ dlqAfterMaxRetries: true, // Move to DLQ after max retries
1273
+
1274
+ // Encryption (Queue-level)
1275
+ encryptionEnabled: false, // Enable AES-256-GCM encryption
1276
+
1277
+ // Retention (Partition-level)
1278
+ retentionSeconds: 0, // Delete pending messages after X seconds
1279
+ completedRetentionSeconds: 0, // Delete completed/failed after X seconds
1280
+ partitionRetentionSeconds: 0, // Delete empty partitions after X seconds
1281
+ retentionEnabled: false, // Enable retention
1282
+
1283
+ // Eviction (Queue-level)
1284
+ maxWaitTimeSeconds: 0 // Evict messages older than X seconds
1285
+ }
1037
1286
  ```
1038
1287
 
1039
- ### Batch Processing with Window Buffer
1288
+ ---
1289
+
1290
+ ## 📚 Full Examples
1291
+
1292
+ ### Example 1: Email Queue with Priority
1040
1293
 
1041
1294
  ```javascript
1042
- // Configure for batch processing
1043
- await client.configure({
1044
- queue: 'analytics',
1045
- options: {
1046
- windowBuffer: 60, // Wait 60 seconds to batch messages
1047
- priority: 3
1048
- }
1295
+ import { Queen } from 'queen-mq';
1296
+
1297
+ const client = new Queen({
1298
+ baseUrls: ['http://localhost:6632']
1049
1299
  });
1050
1300
 
1051
- // Send multiple events
1052
- for (let i = 0; i < 100; i++) {
1053
- await client.push({
1054
- items: [{
1055
- queue: 'analytics',
1056
- partition: 'events',
1057
- payload: { userId: i, action: 'page_view', timestamp: Date.now() }
1058
- }]
1059
- });
1060
- }
1301
+ // Configure queues with different priorities
1302
+ await client.queue('emails-urgent', {
1303
+ priority: 10,
1304
+ leaseTime: 300,
1305
+ retryLimit: 5
1306
+ });
1061
1307
 
1062
- // Messages will be held for 60 seconds to allow batching
1063
- // Then all messages become available at once for efficient processing
1064
- ```
1308
+ await client.queue('emails-normal', {
1309
+ priority: 5,
1310
+ leaseTime: 300,
1311
+ retryLimit: 3
1312
+ });
1065
1313
 
1066
- ### Multi-Queue Processing with Priorities
1314
+ // Producer: Send emails
1315
+ async function sendEmails() {
1316
+ // Urgent email
1317
+ await client.push('emails-urgent', {
1318
+ to: 'admin@company.com',
1319
+ subject: 'Critical Alert',
1320
+ body: 'System issue detected',
1321
+ timestamp: Date.now()
1322
+ });
1067
1323
 
1068
- ```javascript
1069
- // Set up multiple queues with different priorities
1070
- const queues = [
1071
- { name: 'critical-alerts', priority: 100 },
1072
- { name: 'user-notifications', priority: 50 },
1073
- { name: 'background-tasks', priority: 10 }
1074
- ];
1075
-
1076
- for (const queue of queues) {
1077
- await client.configure({
1078
- queue: queue.name,
1079
- options: { priority: queue.priority }
1324
+ // Normal email
1325
+ await client.push('emails-normal', {
1326
+ to: 'user@example.com',
1327
+ subject: 'Welcome',
1328
+ body: 'Thanks for signing up',
1329
+ timestamp: Date.now()
1080
1330
  });
1081
1331
  }
1082
1332
 
1083
- // Consumer that processes all queues by priority
1084
- const stopConsumer = client.consume({
1085
- namespace: 'my-app', // Process all queues in namespace by priority
1086
- handler: async (message) => {
1087
- console.log(`Processing ${message.queue}: ${message.data.type}`);
1088
- await processMessage(message);
1089
- },
1090
- options: { batch: 5, wait: true }
1091
- });
1333
+ // Consumer: Process emails
1334
+ async function processEmails() {
1335
+ // Urgent emails processed first (higher priority)
1336
+ for await (const email of client.take('emails-urgent', {
1337
+ wait: true,
1338
+ timeout: 30000
1339
+ })) {
1340
+ try {
1341
+ console.log('Sending urgent email:', email.data.to);
1342
+ await sendEmail(email.data);
1343
+ await client.ack(email);
1344
+ } catch (error) {
1345
+ console.error('Failed to send email:', error);
1346
+ await client.ack(email, false, { error: error.message });
1347
+ }
1348
+ }
1349
+ }
1350
+
1351
+ // Send batch of emails
1352
+ await sendEmails();
1353
+
1354
+ // Start processing
1355
+ processEmails().catch(console.error);
1092
1356
  ```
1093
1357
 
1094
- ### High-Throughput Batch Processing
1358
+ ### Example 2: Task Pipeline
1095
1359
 
1096
1360
  ```javascript
1097
- // Configure queue for high-throughput batch processing
1098
- await client.configure({
1099
- queue: 'data-processing',
1100
- options: {
1101
- priority: 5,
1102
- leaseTime: 600, // 10 minutes for batch processing
1103
- windowBuffer: 30 // Buffer messages for 30 seconds
1104
- }
1361
+ import { Queen } from 'queen-mq';
1362
+
1363
+ const client = new Queen({
1364
+ baseUrls: ['http://localhost:6632']
1105
1365
  });
1106
1366
 
1107
- // High-performance batch consumer
1108
- const stopConsumer = client.consume({
1109
- queue: 'data-processing',
1110
- partition: 'analytics',
1111
- handlerBatch: async (messages) => {
1112
- const startTime = Date.now();
1113
- console.log(`Processing batch of ${messages.length} analytics events`);
1114
-
1367
+ // Configure pipeline stages
1368
+ await client.queue('stage-1-validate', { priority: 10 });
1369
+ await client.queue('stage-2-process', { priority: 9 });
1370
+ await client.queue('stage-3-finalize', { priority: 8 });
1371
+
1372
+ // Stage 1: Validate
1373
+ async function validateStage() {
1374
+ for await (const msg of client.take('stage-1-validate', { wait: true })) {
1115
1375
  try {
1116
- // Extract all payloads for batch processing
1117
- const events = messages.map(msg => ({
1118
- id: msg.transactionId,
1119
- ...msg.data
1120
- }));
1376
+ const validated = await validate(msg.data);
1377
+ await client.ack(msg);
1121
1378
 
1122
- // Process entire batch efficiently
1123
- await processAnalyticsBatch(events);
1124
-
1125
- const processingTime = Date.now() - startTime;
1126
- console.log(`✅ Batch processed in ${processingTime}ms`);
1379
+ // Pass to next stage
1380
+ await client.push('stage-2-process', validated);
1381
+ } catch (error) {
1382
+ await client.ack(msg, false, { error: error.message });
1383
+ }
1384
+ }
1385
+ }
1386
+
1387
+ // Stage 2: Process
1388
+ async function processStage() {
1389
+ for await (const msg of client.take('stage-2-process', { wait: true })) {
1390
+ try {
1391
+ const processed = await process(msg.data);
1392
+ await client.ack(msg);
1127
1393
 
1394
+ // Pass to next stage
1395
+ await client.push('stage-3-finalize', processed);
1128
1396
  } catch (error) {
1129
- console.error('Batch processing failed:', error);
1130
- throw error; // Will mark all messages as failed
1397
+ await client.ack(msg, false, { error: error.message });
1131
1398
  }
1132
- },
1133
- options: {
1134
- batch: 50, // Process up to 50 messages at once
1135
- wait: true, // Use long polling
1136
- timeout: 30000,
1137
- stopOnError: false
1138
1399
  }
1139
- });
1400
+ }
1140
1401
 
1141
- async function processAnalyticsBatch(events) {
1142
- // Example: Bulk insert to database
1143
- await database.analytics.insertMany(events);
1144
-
1145
- // Example: Send to external analytics service
1146
- await analyticsService.sendBatch(events);
1147
-
1148
- // Example: Update aggregated metrics
1149
- await updateMetrics(events);
1402
+ // Stage 3: Finalize
1403
+ async function finalizeStage() {
1404
+ for await (const msg of client.take('stage-3-finalize', { wait: true })) {
1405
+ try {
1406
+ await finalize(msg.data);
1407
+ await client.ack(msg);
1408
+ console.log('Pipeline complete:', msg.data.id);
1409
+ } catch (error) {
1410
+ await client.ack(msg, false, { error: error.message });
1411
+ }
1412
+ }
1150
1413
  }
1151
- ```
1152
1414
 
1153
- ## ⚡ Performance
1415
+ // Start pipeline
1416
+ Promise.all([
1417
+ validateStage(),
1418
+ processStage(),
1419
+ finalizeStage()
1420
+ ]);
1154
1421
 
1155
- ### Benchmarks
1422
+ // Add work to pipeline
1423
+ await client.push('stage-1-validate', { id: 1, data: 'raw data' });
1424
+ ```
1156
1425
 
1157
- - **Throughput**: 10,000+ messages/second
1158
- - **Latency**: < 10ms for immediate pop operations
1159
- - **Concurrent Connections**: 1,000+ long polling connections
1160
- - **Database**: Optimized for PostgreSQL with proper indexing
1426
+ ### Example 3: Event Streaming (Bus Mode)
1161
1427
 
1162
- ### Optimization Features
1428
+ ```javascript
1429
+ import { Queen } from 'queen-mq';
1163
1430
 
1164
- - **Connection Pooling**: Efficient database connection management
1165
- - **Resource Caching**: In-memory cache for queue/partition lookups
1166
- - **Batch Operations**: Bulk insert/update for high throughput
1167
- - **Optimized Queries**: Carefully crafted SQL with proper indexes
1168
- - **Event-Driven Architecture**: Minimal polling overhead
1431
+ const client = new Queen({
1432
+ baseUrls: ['http://localhost:6632']
1433
+ });
1169
1434
 
1170
- ### Performance Tuning
1435
+ // Configure event queue
1436
+ await client.queue('events', {
1437
+ priority: 10,
1438
+ leaseTime: 60
1439
+ });
1171
1440
 
1172
- ```javascript
1173
- // Environment variables for performance tuning
1174
- export DB_POOL_SIZE=20 // Database connection pool size
1175
- export DB_IDLE_TIMEOUT=30000 // Connection idle timeout
1176
- export DB_CONNECTION_TIMEOUT=2000 // Connection establishment timeout
1177
- ```
1441
+ // Producer: Emit events
1442
+ async function emitEvents() {
1443
+ await client.push('events', {
1444
+ type: 'order.created',
1445
+ orderId: 12345,
1446
+ userId: 789,
1447
+ amount: 99.99,
1448
+ timestamp: Date.now()
1449
+ });
1450
+ }
1178
1451
 
1179
- ## 🔒 Enterprise Features
1452
+ // Consumer 1: Analytics Service
1453
+ async function analyticsService() {
1454
+ for await (const event of client.take('events@analytics', {
1455
+ subscriptionMode: 'all', // Replay all messages
1456
+ wait: true
1457
+ })) {
1458
+ console.log('[Analytics] Processing event:', event.data.type);
1459
+ await updateAnalytics(event.data);
1460
+ await client.ack(event, true, { group: 'analytics' });
1461
+ }
1462
+ }
1180
1463
 
1181
- Queen includes three powerful enterprise features for production deployments:
1464
+ // Consumer 2: Notification Service
1465
+ async function notificationService() {
1466
+ for await (const event of client.take('events@notifications', {
1467
+ subscriptionMode: 'new', // Only new messages
1468
+ wait: true
1469
+ })) {
1470
+ console.log('[Notifications] Processing event:', event.data.type);
1471
+ await sendNotification(event.data);
1472
+ await client.ack(event, true, { group: 'notifications' });
1473
+ }
1474
+ }
1182
1475
 
1183
- ### 1. Encryption
1184
- Protect sensitive data with AES-256-GCM encryption at the queue level.
1476
+ // Consumer 3: Audit Service
1477
+ async function auditService() {
1478
+ for await (const event of client.take('events@audit', {
1479
+ subscriptionMode: 'all', // Log everything
1480
+ wait: true
1481
+ })) {
1482
+ console.log('[Audit] Logging event:', event.data.type);
1483
+ await logToAudit(event.data);
1484
+ await client.ack(event, true, { group: 'audit' });
1485
+ }
1486
+ }
1185
1487
 
1186
- **Setup:**
1187
- ```bash
1188
- # Set encryption key (64 hex characters = 32 bytes)
1189
- export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
1488
+ // Start all services (they all see the same events)
1489
+ Promise.all([
1490
+ analyticsService(),
1491
+ notificationService(),
1492
+ auditService()
1493
+ ]);
1494
+
1495
+ // Emit events
1496
+ await emitEvents();
1190
1497
  ```
1191
1498
 
1192
- **Configuration:**
1499
+ ### Example 4: Batch Processing
1500
+
1193
1501
  ```javascript
1194
- await client.configure({
1195
- queue: 'sensitive-data',
1196
- options: {
1197
- encryptionEnabled: true
1198
- }
1502
+ import { Queen } from 'queen-mq';
1503
+
1504
+ const client = new Queen({
1505
+ baseUrls: ['http://localhost:6632']
1199
1506
  });
1200
- ```
1201
1507
 
1202
- ### 2. Message Retention
1203
- Automatically clean up old messages to prevent storage bloat.
1508
+ // Configure for batch processing
1509
+ await client.queue('data-processing', {
1510
+ priority: 5,
1511
+ leaseTime: 600, // 10 minutes for batch
1512
+ windowBuffer: 30 // Buffer for 30 seconds
1513
+ });
1204
1514
 
1205
- **Configuration:**
1206
- ```javascript
1207
- await client.configure({
1208
- queue: 'temp-queue',
1209
- options: {
1210
- retentionSeconds: 3600, // Delete pending after 1 hour
1211
- completedRetentionSeconds: 300, // Delete completed after 5 minutes
1212
- retentionEnabled: true
1515
+ // Producer: Send data
1516
+ async function sendData() {
1517
+ const records = [];
1518
+ for (let i = 0; i < 1000; i++) {
1519
+ records.push({ id: i, value: Math.random() });
1213
1520
  }
1214
- });
1215
- ```
1521
+
1522
+ // Push in batches
1523
+ await client.push('data-processing/analytics', records);
1524
+ }
1216
1525
 
1217
- **Environment:**
1218
- ```bash
1219
- export RETENTION_INTERVAL=300000 # Cleanup interval in milliseconds
1526
+ // Consumer: Batch processor
1527
+ async function batchProcessor() {
1528
+ const BATCH_SIZE = 100;
1529
+ const batch = [];
1530
+
1531
+ for await (const message of client.take('data-processing/analytics', {
1532
+ batch: BATCH_SIZE,
1533
+ wait: true,
1534
+ timeout: 30000
1535
+ })) {
1536
+ batch.push(message);
1537
+
1538
+ // Process when batch is full
1539
+ if (batch.length >= BATCH_SIZE) {
1540
+ try {
1541
+ console.log(`Processing batch of ${batch.length} records`);
1542
+
1543
+ // Extract data
1544
+ const records = batch.map(m => m.data);
1545
+
1546
+ // Bulk process
1547
+ await bulkInsertToDatabase(records);
1548
+
1549
+ // Acknowledge all
1550
+ for (const msg of batch) {
1551
+ await client.ack(msg);
1552
+ }
1553
+
1554
+ console.log(`✓ Batch complete`);
1555
+ batch.length = 0;
1556
+ } catch (error) {
1557
+ console.error('Batch processing failed:', error);
1558
+
1559
+ // Mark all as failed
1560
+ for (const msg of batch) {
1561
+ await client.ack(msg, false);
1562
+ }
1563
+ batch.length = 0;
1564
+ }
1565
+ }
1566
+ }
1567
+ }
1568
+
1569
+ // Run
1570
+ await sendData();
1571
+ await batchProcessor();
1220
1572
  ```
1221
1573
 
1222
- ### 3. Message Eviction
1223
- Enforce SLAs by automatically evicting messages that wait too long.
1574
+ ### Example 5: Scheduled Jobs
1224
1575
 
1225
- **Configuration:**
1226
1576
  ```javascript
1227
- await client.configure({
1228
- queue: 'time-sensitive',
1229
- options: {
1230
- maxWaitTimeSeconds: 60 // Evict messages older than 1 minute
1231
- }
1577
+ import { Queen } from 'queen-mq';
1578
+
1579
+ const client = new Queen({
1580
+ baseUrls: ['http://localhost:6632']
1232
1581
  });
1233
- ```
1234
1582
 
1235
- **Environment:**
1236
- ```bash
1237
- export EVICTION_INTERVAL=60000 # Check interval in milliseconds
1583
+ // Configure with delayed processing
1584
+ await client.queue('scheduled-jobs', {
1585
+ delayedProcessing: 3600, // 1 hour delay
1586
+ priority: 5
1587
+ });
1588
+
1589
+ // Schedule a job
1590
+ async function scheduleReport() {
1591
+ await client.push('scheduled-jobs/daily-reports', {
1592
+ reportType: 'daily-sales',
1593
+ date: new Date().toISOString().split('T')[0],
1594
+ recipients: ['manager@company.com'],
1595
+ scheduledAt: Date.now()
1596
+ });
1597
+
1598
+ console.log('Report scheduled for processing in 1 hour');
1599
+ }
1600
+
1601
+ // Process scheduled jobs
1602
+ async function processScheduledJobs() {
1603
+ for await (const job of client.take('scheduled-jobs/daily-reports', {
1604
+ wait: true
1605
+ })) {
1606
+ try {
1607
+ console.log('Generating report:', job.data.reportType);
1608
+ await generateReport(job.data);
1609
+ await client.ack(job);
1610
+ } catch (error) {
1611
+ await client.ack(job, false, { error: error.message });
1612
+ }
1613
+ }
1614
+ }
1615
+
1616
+ await scheduleReport();
1617
+ processScheduledJobs().catch(console.error);
1238
1618
  ```
1239
1619
 
1240
- ### Combined Example
1620
+ ### Example 6: Rate Limiting
1621
+
1241
1622
  ```javascript
1242
- await client.configure({
1243
- queue: 'production-queue',
1244
- options: {
1245
- // Encryption
1246
- encryptionEnabled: true,
1247
-
1248
- // Retention
1249
- retentionSeconds: 86400,
1250
- completedRetentionSeconds: 3600,
1251
- retentionEnabled: true,
1252
-
1253
- // Eviction
1254
- maxWaitTimeSeconds: 600,
1623
+ import { Queen } from 'queen-mq';
1624
+
1625
+ const client = new Queen({
1626
+ baseUrls: ['http://localhost:6632']
1627
+ });
1628
+
1629
+ await client.queue('api-calls', {
1630
+ priority: 5,
1631
+ leaseTime: 60
1632
+ });
1633
+
1634
+ // Producer: Queue API calls
1635
+ async function queueApiCalls(calls) {
1636
+ await client.push('api-calls', calls);
1637
+ }
1638
+
1639
+ // Consumer: Rate-limited processor (10 calls per second max)
1640
+ async function rateLimitedProcessor() {
1641
+ const RATE_LIMIT = 10; // calls per second
1642
+ const INTERVAL = 1000; // 1 second
1643
+
1644
+ let callsThisInterval = 0;
1645
+ let intervalStart = Date.now();
1646
+
1647
+ for await (const call of client.take('api-calls', { wait: true })) {
1648
+ // Check if we need to wait
1649
+ if (callsThisInterval >= RATE_LIMIT) {
1650
+ const elapsed = Date.now() - intervalStart;
1651
+ if (elapsed < INTERVAL) {
1652
+ await new Promise(r => setTimeout(r, INTERVAL - elapsed));
1653
+ }
1654
+ callsThisInterval = 0;
1655
+ intervalStart = Date.now();
1656
+ }
1255
1657
 
1256
- // Standard options
1257
- priority: 10,
1258
- leaseTime: 300
1658
+ try {
1659
+ await makeApiCall(call.data);
1660
+ await client.ack(call);
1661
+ callsThisInterval++;
1662
+ } catch (error) {
1663
+ await client.ack(call, false, { error: error.message });
1664
+ }
1259
1665
  }
1260
- });
1666
+ }
1667
+
1668
+ // Generate calls
1669
+ const calls = Array.from({ length: 100 }, (_, i) => ({
1670
+ id: i,
1671
+ endpoint: '/api/data',
1672
+ method: 'GET'
1673
+ }));
1674
+
1675
+ await queueApiCalls(calls);
1676
+ rateLimitedProcessor().catch(console.error);
1261
1677
  ```
1262
1678
 
1263
- ## ⚙️ Configuration
1679
+ ### Example 7: Enterprise Features
1264
1680
 
1265
- ### Environment Variables
1681
+ ```javascript
1682
+ import { Queen } from 'queen-mq';
1266
1683
 
1267
- All configuration values have sensible defaults and can be overridden using environment variables. Configuration is centralized in `src/config.js`.
1684
+ const client = new Queen({
1685
+ baseUrls: ['http://localhost:6632']
1686
+ });
1268
1687
 
1269
- #### Server Configuration
1688
+ // Configure with all enterprise features
1689
+ await client.queue('production-queue', {
1690
+ // Encryption
1691
+ encryptionEnabled: true,
1692
+
1693
+ // Retention
1694
+ retentionSeconds: 86400, // Delete pending after 24 hours
1695
+ completedRetentionSeconds: 3600, // Delete completed after 1 hour
1696
+ retentionEnabled: true,
1697
+
1698
+ // Eviction (SLA enforcement)
1699
+ maxWaitTimeSeconds: 600, // Evict messages older than 10 minutes
1700
+
1701
+ // Standard options
1702
+ priority: 10,
1703
+ leaseTime: 300,
1704
+ retryLimit: 3,
1705
+ dlqAfterMaxRetries: true
1706
+ });
1270
1707
 
1271
- ```bash
1272
- # Server basics
1273
- PORT=6632 # Server port (default: 6632)
1274
- HOST=0.0.0.0 # Server host (default: 0.0.0.0)
1275
- WORKER_ID=worker-1 # Worker identifier (default: worker-${process.pid})
1276
- APP_NAME=queen-uws # Application name for database connections
1708
+ // Push sensitive data (will be encrypted)
1709
+ await client.push('production-queue', {
1710
+ userId: 123,
1711
+ creditCard: '4111-1111-1111-1111',
1712
+ amount: 99.99,
1713
+ timestamp: Date.now()
1714
+ });
1277
1715
 
1278
- # CORS settings
1279
- CORS_MAX_AGE=86400 # CORS max age in seconds (default: 86400 = 24 hours)
1280
- CORS_ALLOWED_ORIGINS=* # Allowed origins (default: *)
1281
- CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,OPTIONS # Allowed methods
1282
- CORS_ALLOWED_HEADERS=Content-Type,Authorization # Allowed headers
1716
+ // Process (data decrypted automatically)
1717
+ for await (const message of client.take('production-queue', { wait: true })) {
1718
+ console.log('Processing encrypted data:', message.data.userId);
1719
+ await processPayment(message.data);
1720
+ await client.ack(message);
1721
+ }
1283
1722
  ```
1284
1723
 
1285
- #### Database Configuration
1724
+ ---
1286
1725
 
1287
- ```bash
1288
- # Connection settings
1289
- PG_USER=postgres # PostgreSQL user (default: postgres)
1290
- PG_HOST=localhost # PostgreSQL host (default: localhost)
1291
- PG_DB=postgres # PostgreSQL database (default: postgres)
1292
- PG_PASSWORD=postgres # PostgreSQL password (default: postgres)
1293
- PG_PORT=5432 # PostgreSQL port (default: 5432)
1726
+ ## 🧪 Testing
1294
1727
 
1295
- # Connection pool settings
1296
- DB_POOL_SIZE=20 # Max pool size (default: 20)
1297
- DB_IDLE_TIMEOUT=30000 # Idle connection timeout in ms (default: 30000)
1298
- DB_CONNECTION_TIMEOUT=2000 # Connection timeout in ms (default: 2000)
1299
- DB_STATEMENT_TIMEOUT=30000 # Statement timeout in ms (default: 30000)
1300
- DB_QUERY_TIMEOUT=30000 # Query timeout in ms (default: 30000)
1301
- DB_MAX_RETRIES=3 # Max retry attempts for queries (default: 3)
1302
- ```
1728
+ Queen includes a comprehensive test suite covering all features.
1303
1729
 
1304
- #### Queue Processing Configuration
1730
+ ### Run Tests
1305
1731
 
1306
1732
  ```bash
1307
- # Pop operation defaults
1308
- DEFAULT_TIMEOUT=30000 # Default pop timeout in ms (default: 30000)
1309
- MAX_TIMEOUT=60000 # Maximum pop timeout in ms (default: 60000)
1310
- DEFAULT_BATCH_SIZE=1 # Default batch size for pop (default: 1)
1311
- BATCH_INSERT_SIZE=1000 # Batch size for bulk inserts (default: 1000)
1733
+ # Start the server first
1734
+ npm start
1312
1735
 
1313
- # Long polling
1314
- QUEUE_POLL_INTERVAL=100 # Poll interval in ms (default: 100)
1315
- QUEUE_POLL_INTERVAL_FILTERED=1000 # Poll interval for filtered pops (default: 1000)
1736
+ # Run all tests
1737
+ node src/test/test-new.js
1316
1738
 
1317
- # Queue defaults
1318
- DEFAULT_LEASE_TIME=300 # Default lease time in seconds (default: 300 = 5 minutes)
1319
- DEFAULT_RETRY_LIMIT=3 # Default retry limit (default: 3)
1320
- DEFAULT_RETRY_DELAY=1000 # Default retry delay in ms (default: 1000)
1321
- DEFAULT_MAX_SIZE=10000 # Default max queue size (default: 10000)
1322
- DEFAULT_TTL=3600 # Default TTL in seconds (default: 3600 = 1 hour)
1323
- DEFAULT_PRIORITY=0 # Default queue priority (default: 0)
1324
- DEFAULT_DELAYED_PROCESSING=0 # Default delayed processing in seconds (default: 0)
1325
- DEFAULT_WINDOW_BUFFER=0 # Default window buffer in seconds (default: 0)
1739
+ # Run specific test categories
1740
+ node src/test/test-new.js core # Core features
1741
+ node src/test/test-new.js partition # Partition locking
1742
+ node src/test/test-new.js enterprise # Enterprise features
1743
+ node src/test/test-new.js bus # Bus mode
1744
+ node src/test/test-new.js edge # Edge cases
1745
+ node src/test/test-new.js advanced # Advanced patterns
1326
1746
 
1327
- # Dead Letter Queue
1328
- DEFAULT_DLQ_ENABLED=false # Enable DLQ by default (default: false)
1329
- DEFAULT_DLQ_AFTER_MAX_RETRIES=false # Move to DLQ after max retries (default: false)
1747
+ # Show help
1748
+ node src/test/test-new.js help
1749
+ ```
1330
1750
 
1331
- # Retention
1332
- DEFAULT_RETENTION_SECONDS=0 # Default retention for all messages (default: 0 = disabled)
1333
- DEFAULT_COMPLETED_RETENTION_SECONDS=0 # Retention for completed messages (default: 0)
1334
- DEFAULT_RETENTION_ENABLED=false # Enable retention by default (default: false)
1751
+ ### Test Coverage
1335
1752
 
1336
- # Eviction
1337
- DEFAULT_MAX_WAIT_TIME_SECONDS=0 # Max wait time before eviction (default: 0 = disabled)
1338
- ```
1753
+ The test suite verifies:
1339
1754
 
1340
- #### Background Jobs Configuration
1755
+ **Core Features:**
1756
+ - Queue creation and configuration
1757
+ - Single and batch message push
1758
+ - Message take and acknowledgment
1759
+ - Delayed processing
1760
+ - Partition FIFO ordering
1761
+
1762
+ **Partition Locking:**
1763
+ - Lock acquisition and release
1764
+ - Bus mode partition locking
1765
+ - Specific partition locking
1766
+ - Namespace/task filtering with locking
1767
+
1768
+ **Enterprise Features:**
1769
+ - AES-256-GCM encryption
1770
+ - Message retention policies
1771
+ - Message eviction
1772
+ - Combined enterprise features
1773
+
1774
+ **Bus Mode:**
1775
+ - Consumer groups
1776
+ - Subscription modes (all, new, from)
1777
+ - Consumer group isolation
1778
+ - Mixed mode (queue + bus)
1779
+
1780
+ **Edge Cases:**
1781
+ - Empty and null payloads
1782
+ - Very large payloads
1783
+ - Concurrent operations
1784
+ - Lease expiration
1785
+ - SQL injection prevention
1786
+ - XSS prevention
1787
+
1788
+ **Advanced Patterns:**
1789
+ - Multi-stage pipelines
1790
+ - Fan-out/fan-in
1791
+ - Priority scenarios
1792
+ - Dead letter queue
1793
+ - Circuit breaker
1794
+ - Message deduplication
1795
+ - Event sourcing
1341
1796
 
1342
- ```bash
1343
- # Job intervals
1344
- LEASE_RECLAIM_INTERVAL=5000 # Lease reclamation interval in ms (default: 5000)
1345
- RETENTION_INTERVAL=300000 # Retention check interval in ms (default: 300000 = 5 minutes)
1346
- RETENTION_BATCH_SIZE=1000 # Retention batch size (default: 1000)
1347
- PARTITION_CLEANUP_DAYS=7 # Days before cleaning empty partitions (default: 7)
1348
- EVICTION_INTERVAL=60000 # Eviction check interval in ms (default: 60000 = 1 minute)
1349
- EVICTION_BATCH_SIZE=1000 # Eviction batch size (default: 1000)
1797
+ ### Test Results
1350
1798
 
1351
- # WebSocket updates
1352
- QUEUE_DEPTH_UPDATE_INTERVAL=5000 # Queue depth update interval (default: 5000)
1353
- SYSTEM_STATS_UPDATE_INTERVAL=10000 # System stats update interval (default: 10000)
1799
+ Example output:
1354
1800
  ```
1801
+ 🚀 Starting Queen Message Queue Test Suite
1802
+ Using the new minimalist Queen client interface
1803
+ ================================================================================
1355
1804
 
1356
- #### WebSocket Configuration
1805
+ 📦 CORE FEATURES
1806
+ ----------------------------------------
1807
+ ✅ Queue Creation Policy
1808
+ ✅ Single Message Push
1809
+ ✅ Batch Message Push
1810
+ ✅ Queue Configuration
1811
+ ✅ Take and Acknowledgment
1812
+ ✅ Delayed Processing
1813
+ ✅ Partition FIFO Ordering
1357
1814
 
1358
- ```bash
1359
- # WebSocket settings
1360
- WS_COMPRESSION=0 # Compression level (default: 0 = disabled)
1361
- WS_MAX_PAYLOAD_LENGTH=16384 # Max payload length in bytes (default: 16384 = 16KB)
1362
- WS_IDLE_TIMEOUT=60 # Idle timeout in seconds (default: 60)
1363
- WS_MAX_CONNECTIONS=1000 # Max concurrent connections (default: 1000)
1364
- WS_HEARTBEAT_INTERVAL=30000 # Heartbeat interval in ms (default: 30000)
1815
+ 🔒 PARTITION LOCKING
1816
+ ----------------------------------------
1817
+ ✅ Partition Locking
1818
+ ✅ Bus Partition Locking
1819
+ ✅ Specific Partition Locking
1820
+ ✅ Namespace Task Filtering
1821
+ ✅ Namespace Task Bus Mode
1822
+
1823
+ 📈 Test Summary
1824
+ ================================================================================
1825
+ Total: 42 | Passed: 42 | Failed: 0 | Duration: 45.2s
1365
1826
  ```
1366
1827
 
1367
- #### Encryption Configuration
1828
+ ---
1368
1829
 
1369
- ```bash
1370
- # Encryption settings
1371
- QUEEN_ENCRYPTION_KEY=<64-hex> # 32-byte key as 64 hex characters
1372
- # Generate with: openssl rand -hex 32
1373
- # Required for encryption features
1374
- ```
1830
+ ## 🤝 Contributing
1375
1831
 
1376
- #### Client SDK Configuration
1832
+ We welcome contributions! Here's how to get started:
1377
1833
 
1378
- ```bash
1379
- # Client defaults
1380
- QUEEN_BASE_URL=http://localhost:6632 # Default server URL
1381
- CLIENT_RETRY_ATTEMPTS=3 # Default retry attempts (default: 3)
1382
- CLIENT_RETRY_DELAY=1000 # Default retry delay in ms (default: 1000)
1383
- CLIENT_RETRY_BACKOFF=2 # Retry backoff multiplier (default: 2)
1384
- CLIENT_POOL_SIZE=10 # Client connection pool size (default: 10)
1385
- CLIENT_REQUEST_TIMEOUT=30000 # Request timeout in ms (default: 30000)
1386
- ```
1834
+ 1. **Fork the repository**
1835
+ 2. **Create a feature branch**: `git checkout -b feature/amazing-feature`
1836
+ 3. **Make your changes**
1837
+ 4. **Run the test suite**: `node src/test/test-new.js`
1838
+ 5. **Commit your changes**: `git commit -m 'Add amazing feature'`
1839
+ 6. **Push to the branch**: `git push origin feature/amazing-feature`
1840
+ 7. **Open a Pull Request**
1387
1841
 
1388
- #### API Configuration
1842
+ ### Development Setup
1389
1843
 
1390
1844
  ```bash
1391
- # Pagination
1392
- API_DEFAULT_LIMIT=100 # Default page size (default: 100)
1393
- API_MAX_LIMIT=1000 # Maximum page size (default: 1000)
1394
- API_DEFAULT_OFFSET=0 # Default offset (default: 0)
1395
- ```
1845
+ # Clone your fork
1846
+ git clone https://github.com/your-username/queen
1847
+ cd queen
1396
1848
 
1397
- #### Analytics Configuration
1849
+ # Install dependencies
1850
+ nvm use 22
1851
+ npm install
1398
1852
 
1399
- ```bash
1400
- # Analytics settings
1401
- ANALYTICS_RECENT_HOURS=24 # Hours to consider for recent stats (default: 24)
1402
- ANALYTICS_MIN_COMPLETED=5 # Min completed messages for stats (default: 5)
1403
- RECENT_MESSAGE_WINDOW=60 # Recent message window in seconds (default: 60)
1404
- RELATED_MESSAGE_WINDOW=3600 # Related message window in seconds (default: 3600)
1405
- MAX_RELATED_MESSAGES=10 # Max related messages to return (default: 10)
1406
- ```
1853
+ # Initialize database
1854
+ node init-db.js
1407
1855
 
1408
- #### Monitoring Configuration
1856
+ # Start server
1857
+ npm start
1409
1858
 
1410
- ```bash
1411
- # Performance monitoring
1412
- ENABLE_REQUEST_COUNTING=true # Enable request counting (default: true)
1413
- ENABLE_MESSAGE_COUNTING=true # Enable message counting (default: true)
1414
- METRICS_ENDPOINT_ENABLED=true # Enable /metrics endpoint (default: true)
1415
- HEALTH_CHECK_ENABLED=true # Enable /health endpoint (default: true)
1859
+ # Run tests
1860
+ node src/test/test-new.js
1416
1861
  ```
1417
1862
 
1418
- #### Logging Configuration
1863
+ ### Code Style
1419
1864
 
1420
- ```bash
1421
- # Logging settings
1422
- ENABLE_LOGGING=true # Enable logging (default: true)
1423
- LOG_LEVEL=info # Log level (default: info)
1424
- LOG_FORMAT=json # Log format (default: json)
1425
- LOG_TIMESTAMP=true # Include timestamps (default: true)
1426
- ```
1865
+ - Use ES6+ features
1866
+ - Follow existing code style
1867
+ - Add comments for complex logic
1868
+ - Write tests for new features
1427
1869
 
1428
- ### Queue Options
1870
+ ---
1429
1871
 
1430
- ```javascript
1431
- {
1432
- // Standard Options
1433
- "leaseTime": 300, // Seconds before message lease expires
1434
- "retryLimit": 3, // Maximum retry attempts
1435
- "priority": 0, // Queue/partition priority (higher = first)
1436
- "delayedProcessing": 0, // Delay in seconds before message is available
1437
- "windowBuffer": 0, // Buffer time in seconds for batching
1438
- "dlqAfterMaxRetries": true, // Move to dead letter queue after max retries
1439
-
1440
- // Encryption (Queue-level)
1441
- "encryptionEnabled": false, // Enable AES-256-GCM encryption for this queue
1442
-
1443
- // Retention (Partition-level)
1444
- "retentionSeconds": 0, // Delete pending messages after X seconds (0 = disabled)
1445
- "completedRetentionSeconds": 0, // Delete completed/failed messages after X seconds
1446
- "partitionRetentionSeconds": 0, // Delete empty partitions after X seconds
1447
- "retentionEnabled": false, // Enable retention for this partition
1448
-
1449
- // Eviction (Queue-level)
1450
- "maxWaitTimeSeconds": 0 // Evict messages older than X seconds (0 = disabled)
1451
- }
1452
- ```
1872
+ ## 📄 License
1453
1873
 
1454
- ## 🧪 Testing
1874
+ Apache License 2.0 - see [LICENSE.md](LICENSE.md) for details.
1455
1875
 
1456
- ### Run Core Feature Tests
1876
+ ---
1457
1877
 
1458
- ```bash
1459
- # Start the server
1460
- npm start
1878
+ ## 🔗 Links
1461
1879
 
1462
- # Run comprehensive test suite
1463
- node src/test/core-features-test.js
1880
+ - **Repository**: [github.com/smartpricing/queen](https://github.com/smartpricing/queen)
1881
+ - **Documentation**: See `docs/` directory
1882
+ - **Issues**: [GitHub Issues](https://github.com/smartpricing/queen/issues)
1883
+ - **API Reference**: [API.md](API.md)
1464
1884
 
1465
- # Run full test suite (more detailed)
1466
- node src/test/comprehensive-test.js
1467
- ```
1885
+ ---
1468
1886
 
1469
- ### Test Results
1887
+ ## 📈 Performance
1470
1888
 
1471
- The test suite verifies:
1472
- - ✅ Single and batch message push
1473
- - ✅ Queue configuration and options
1474
- - ✅ Pop operations (specific partition and queue-level)
1475
- - ✅ Delayed processing (2+ second delays)
1476
- - ✅ Partition priority ordering
1477
- - ✅ Consumer pattern with automatic acknowledgment
1478
- - ✅ Message acknowledgment and retry logic
1479
- - ✅ FIFO ordering within partitions
1889
+ **Benchmarks** (PostgreSQL 16, Node.js 22):
1890
+ - **Throughput**: 10,000+ messages/second
1891
+ - **Latency**: < 10ms for immediate pop operations
1892
+ - **Concurrent Connections**: 1,000+ long polling connections
1893
+ - **Database**: Optimized with proper indexing and connection pooling
1480
1894
 
1481
- ## 🤝 Contributing
1895
+ **Optimization Features:**
1896
+ - Connection pooling with configurable size
1897
+ - Resource caching for queue/partition lookups
1898
+ - Batch operations for bulk inserts/updates
1899
+ - Optimized SQL queries with proper indexes
1900
+ - Event-driven architecture for minimal polling overhead
1901
+ - Long polling for real-time message delivery
1482
1902
 
1483
- 1. Fork the repository
1484
- 2. Create a feature branch
1485
- 3. Make your changes
1486
- 4. Run the test suite
1487
- 5. Submit a pull request
1903
+ ---
1488
1904
 
1489
- ## 📄 License
1905
+ ## 🎯 Roadmap
1490
1906
 
1491
- MIT License - see LICENSE file for details.
1907
+ - [ ] **Horizontal Scaling**: Better support for multiple server instances
1908
+ - [ ] **Message Scheduling**: Cron-like scheduling for recurring jobs
1909
+ - [ ] **Priority Lanes**: Dynamic priority adjustment based on load
1910
+ - [ ] **Metrics Export**: Prometheus/Grafana integration
1911
+ - [ ] **Admin API**: REST API for queue management
1912
+ - [ ] **Client Libraries**: Python, Go, Java clients
1913
+ - [ ] **Message Tracing**: Distributed tracing integration
1914
+ - [ ] **Queue Templates**: Pre-configured queue patterns
1915
+ - [ ] **GraphQL API**: Alternative to REST API
1916
+ - [ ] **Kubernetes Operator**: Native K8s support
1492
1917
 
1493
1918
  ---
1494
1919
 
1495
- **Queen Message Queue System** - Built for performance, reliability, and scalability. 🚀
1920
+ <div align="center">
1921
+
1922
+ **Queen Message Queue System** - Built for performance, reliability, and developer happiness 🚀
1923
+
1924
+ Made with ❤️ by [Smartpricing](https://github.com/smartpricing)
1925
+
1926
+ </div>