queen-mq 0.1.0 โ†’ 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (160) hide show
  1. package/API.md +862 -752
  2. package/AUTH.md +2044 -0
  3. package/LICENSE.md +202 -0
  4. package/README.md +1705 -1051
  5. package/WEBAPP.md +1889 -0
  6. package/assets/dashboard-01.png +0 -0
  7. package/assets/queen-logo-blue.svg +210 -0
  8. package/assets/queen-logo-cyan.svg +210 -0
  9. package/assets/queen-logo-indigo.svg +210 -0
  10. package/assets/queen-logo-orange.svg +210 -0
  11. package/assets/queen-logo-pink.svg +210 -0
  12. package/assets/queen-logo-purple.svg +210 -0
  13. package/assets/queen-logo-rose.svg +239 -0
  14. package/assets/queen-logo.svg +263 -0
  15. package/examples/batch-processing.js +58 -0
  16. package/examples/test-complete-client.js +260 -0
  17. package/examples/test-dashboard-api.js +200 -0
  18. package/examples/test-traceid.js +147 -0
  19. package/package.json +17 -4
  20. package/server.log +1 -0
  21. package/src/benchmark/consumer.js +207 -0
  22. package/src/benchmark/consumer_multi.js +216 -0
  23. package/src/benchmark/producer.js +75 -0
  24. package/src/benchmark/producer_multi.js +115 -0
  25. package/src/client/client.js +300 -31
  26. package/src/client/queenClient.js +5 -0
  27. package/src/cluster-server.js +242 -0
  28. package/src/config.js +19 -5
  29. package/src/database/connection.js +42 -16
  30. package/src/database/poolManager.js +7 -0
  31. package/src/database/schema-v2.sql +194 -130
  32. package/src/managers/queueManagerOptimized.js +823 -933
  33. package/src/managers/systemEventManager.js +8 -3
  34. package/src/routes/messages.js +127 -57
  35. package/src/routes/pop.js +27 -43
  36. package/src/routes/resources.js +61 -27
  37. package/src/routes/status.js +1037 -0
  38. package/src/server.js +308 -272
  39. package/src/services/evictionService.js +57 -28
  40. package/src/services/retentionService.js +44 -11
  41. package/src/test/MIGRATION_ISSUES.md +174 -0
  42. package/src/test/README.md +203 -0
  43. package/src/test/advanced-pattern-tests.js +1137 -0
  44. package/src/test/bus-mode-tests.js +361 -0
  45. package/src/test/core-tests.js +342 -0
  46. package/src/test/edge-case-tests.js +561 -0
  47. package/src/test/enterprise-tests.js +637 -0
  48. package/src/test/partition-locking-tests.js +545 -0
  49. package/src/test/test-new.js +278 -0
  50. package/src/test/test.js +6 -3
  51. package/src/test/utils.js +169 -0
  52. package/src/utils/streaming.js +231 -0
  53. package/src/utils/uuid.js +2 -2
  54. package/src/websocket/wsServer.js +10 -3
  55. package/test-keepalive-v2.sh +22 -0
  56. package/webapp/COLOR_GUIDE.md +118 -0
  57. package/webapp/README.md +143 -0
  58. package/webapp/index.html +14 -0
  59. package/webapp/package-lock.json +3184 -0
  60. package/webapp/package.json +25 -0
  61. package/webapp/postcss.config.js +7 -0
  62. package/webapp/public/assets/queen-logo-blue.svg +210 -0
  63. package/webapp/public/assets/queen-logo-cyan.svg +210 -0
  64. package/webapp/public/assets/queen-logo-indigo.svg +210 -0
  65. package/webapp/public/assets/queen-logo-orange.svg +210 -0
  66. package/webapp/public/assets/queen-logo-pink.svg +210 -0
  67. package/webapp/public/assets/queen-logo-purple.svg +210 -0
  68. package/webapp/public/assets/queen-logo-rose.svg +239 -0
  69. package/webapp/public/assets/queen-logo.svg +263 -0
  70. package/webapp/src/App.vue +19 -0
  71. package/webapp/src/api/analytics.js +10 -0
  72. package/webapp/src/api/client.js +29 -0
  73. package/webapp/src/api/consumers.js +52 -0
  74. package/webapp/src/api/health.js +7 -0
  75. package/webapp/src/api/messages.js +26 -0
  76. package/webapp/src/api/queues.js +14 -0
  77. package/webapp/src/api/resources.js +8 -0
  78. package/webapp/src/assets/styles/main.css +357 -0
  79. package/webapp/src/components/analytics/AnalyticsFilters.vue +87 -0
  80. package/webapp/src/components/analytics/AnalyticsMetrics.vue +57 -0
  81. package/webapp/src/components/analytics/MessageDistributionChart.vue +111 -0
  82. package/webapp/src/components/analytics/MessageFlowChart.vue +173 -0
  83. package/webapp/src/components/analytics/TimeRangeSelector.vue +27 -0
  84. package/webapp/src/components/analytics/TopQueuesChart.vue +132 -0
  85. package/webapp/src/components/common/ConfirmDialog.vue +56 -0
  86. package/webapp/src/components/common/LoadingSpinner.vue +6 -0
  87. package/webapp/src/components/common/MetricCard.vue +43 -0
  88. package/webapp/src/components/common/StatusBadge.vue +45 -0
  89. package/webapp/src/components/dashboard/MessageStatusCard.vue +50 -0
  90. package/webapp/src/components/dashboard/PerformanceCard.vue +38 -0
  91. package/webapp/src/components/dashboard/ThroughputChart.vue +182 -0
  92. package/webapp/src/components/dashboard/TopQueuesTable.vue +53 -0
  93. package/webapp/src/components/layout/AppLayout.vue +110 -0
  94. package/webapp/src/components/layout/AppSidebar.vue +304 -0
  95. package/webapp/src/components/messages/MessageDetailPanel.vue +242 -0
  96. package/webapp/src/components/messages/MessageFilters.vue +114 -0
  97. package/webapp/src/components/queue-detail/PartitionList.vue +79 -0
  98. package/webapp/src/components/queue-detail/PushMessageModal.vue +175 -0
  99. package/webapp/src/components/queue-detail/QueueConfig.vue +63 -0
  100. package/webapp/src/components/queue-detail/QueueDetailHeader.vue +53 -0
  101. package/webapp/src/components/queue-detail/RecentMessages.vue +76 -0
  102. package/webapp/src/components/queues/CreateQueueModal.vue +193 -0
  103. package/webapp/src/components/queues/QueueFilters.vue +90 -0
  104. package/webapp/src/composables/useApi.js +34 -0
  105. package/webapp/src/composables/useTheme.js +36 -0
  106. package/webapp/src/main.js +11 -0
  107. package/webapp/src/router/index.js +42 -0
  108. package/webapp/src/utils/colors.js +96 -0
  109. package/webapp/src/utils/formatters.js +49 -0
  110. package/webapp/src/views/Analytics.vue +377 -0
  111. package/webapp/src/views/ConsumerGroups.vue +433 -0
  112. package/webapp/src/views/Dashboard.vue +418 -0
  113. package/webapp/src/views/Messages.vue +361 -0
  114. package/webapp/src/views/QueueDetail.vue +582 -0
  115. package/webapp/src/views/Queues.vue +496 -0
  116. package/webapp/tailwind.config.js +25 -0
  117. package/webapp/vite.config.js +10 -0
  118. package/CACHE.md +0 -519
  119. package/DASHBOARD-V3.md +0 -478
  120. package/DASHBOARD.md +0 -382
  121. package/MOD_QUEUE.md +0 -453
  122. package/PARTITION_LOCKING_DESIGN.md +0 -989
  123. package/PLAN.md +0 -707
  124. package/QUERY_ANALSYS.md +0 -72
  125. package/QUEUE_BUS.md +0 -334
  126. package/V2-PLAN.md +0 -236
  127. package/dashboard/.vscode/extensions.json +0 -3
  128. package/dashboard/README.md +0 -5
  129. package/dashboard/index.html +0 -14
  130. package/dashboard/package-lock.json +0 -1458
  131. package/dashboard/package.json +0 -25
  132. package/dashboard/public/vite.svg +0 -1
  133. package/dashboard/src/App.vue +0 -29
  134. package/dashboard/src/assets/styles/main.css +0 -908
  135. package/dashboard/src/assets/vue.svg +0 -1
  136. package/dashboard/src/components/cards/MetricCard.vue +0 -298
  137. package/dashboard/src/components/charts/QueueDepthChart.vue +0 -276
  138. package/dashboard/src/components/charts/QueueLagChart.vue +0 -436
  139. package/dashboard/src/components/charts/ThroughputChart.vue +0 -302
  140. package/dashboard/src/components/common/ActivityFeed.vue +0 -251
  141. package/dashboard/src/components/layout/AppHeader.vue +0 -208
  142. package/dashboard/src/components/layout/AppLayout.vue +0 -88
  143. package/dashboard/src/components/layout/AppSidebar.vue +0 -261
  144. package/dashboard/src/main.js +0 -44
  145. package/dashboard/src/router.js +0 -54
  146. package/dashboard/src/services/api.js +0 -187
  147. package/dashboard/src/services/websocket.js +0 -167
  148. package/dashboard/src/utils/constants.js +0 -56
  149. package/dashboard/src/utils/helpers.js +0 -118
  150. package/dashboard/src/views/Analytics.vue +0 -912
  151. package/dashboard/src/views/Dashboard.vue +0 -906
  152. package/dashboard/src/views/Messages.vue +0 -437
  153. package/dashboard/src/views/QueueDetail.vue +0 -501
  154. package/dashboard/src/views/Queues.vue +0 -333
  155. package/dashboard/vite.config.js +0 -30
  156. package/debug-namespace.js +0 -110
  157. package/docs/long-polling.md +0 -159
  158. package/docs/multi-server-cache-solutions.md +0 -185
  159. package/docs/performance-tuning.md +0 -222
  160. package/src/routes/analytics.js +0 -812
package/README.md CHANGED
@@ -1,40 +1,123 @@
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
4
 
5
- ![Queen Dashboard](assets/dashboard.png)
5
+ **A modern, high-performance message queue system built on PostgreSQL**
6
6
 
7
- ## ๐Ÿš€ Features
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/)
8
9
 
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
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
+ <p align="center">
13
+ <img src="assets/queen-logo.svg" alt="Queen Logo" width="120" />
14
+ </p>
15
+
16
+ </div>
17
+
18
+ ---
19
+
20
+ ## ๐ŸŽฏ Introduction
21
+
22
+ **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.
23
+
24
+ ### Why Queen?
25
+
26
+ **๐Ÿš€ Developer-First API**
27
+ - **4 core methods, infinite patterns**: `queue()`, `push()`, `take()`, `ack()`
28
+ - **Async iteration**: Process messages with familiar `for await` syntax
29
+ - **Batch processing**: Use `takeBatch()` for 250k+ msg/sec throughput on millions of messages
30
+ - **Smart addressing**: `orders/urgent@workers` - queue, partition, and consumer group in one
31
+
32
+ **โšก Production-Ready Performance**
33
+ - **100,000+ msg/sec** throughput with cursor-based consumption
34
+ - **Constant-time batch operations** - O(batch_size) regardless of queue depth
35
+ - **Long polling** for event-driven, real-time message delivery
36
+ - **Partition locking** prevents duplicate processing across consumers
37
+ - **Connection pooling** and optimized batch operations
38
+
39
+ **๐Ÿ—๏ธ Flexible Architecture**
40
+ - **Queue Mode**: Competitive consumption (traditional work queue)
41
+ - **Bus Mode**: Pub/sub with consumer groups (event streaming)
42
+ - **Mixed Mode**: Combine both patterns in the same system
43
+ - **Partitions**: FIFO ordering with parallel processing
44
+
45
+ **๐Ÿ”’ Enterprise Features**
46
+ - **AES-256-GCM Encryption**: Protect sensitive data at rest
47
+ - **Message Retention**: Automatic cleanup policies
48
+ - **Message Eviction**: SLA enforcement for time-sensitive tasks
49
+ - **Dead Letter Queue**: Handle failed messages gracefully
50
+
51
+ **๐Ÿ“Š Built-in Observability**
52
+ - **Real-time Dashboard**: WebSocket-powered monitoring
53
+ - **Rich Analytics**: Throughput, lag, queue depth metrics
54
+ - **Message Browser**: Search, inspect, and retry messages
55
+ - **System Health**: Database, memory, and performance metrics
56
+ - **Cursor Tracking**: Monitor consumption progress per consumer group
57
+
58
+ ### Use Cases
59
+
60
+ - **Task Queues**: Background jobs, email sending, data processing
61
+ - **Event Streaming**: Audit logs, analytics, multi-service event handling
62
+ - **Workflow Orchestration**: Multi-stage pipelines, saga patterns
63
+ - **Rate Limiting**: Throttle and batch time-sensitive operations
64
+ - **Priority Processing**: Handle urgent tasks before routine ones
65
+
66
+ ---
19
67
 
20
68
  ## ๐Ÿ“‹ Table of Contents
21
69
 
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)
70
+ - [First Queue](#-first-queue)
71
+ - [Quick Start](#-quick-start)
72
+ - [Client Examples](#-client-examples)
73
+ - [Server Setup](#-server-setup)
74
+ - [Core Concepts](#-core-concepts)
75
+ - [Cursor-Based Consumption Strategy](#-cursor-based-consumption-strategy)
76
+ - [HTTP API Reference](#-http-api-reference)
77
+ - [Dashboard](#-dashboard)
78
+ - [Configuration](#-configuration)
79
+ - [Full Examples](#-full-examples)
80
+ - [Testing](#-testing)
81
+ - [Contributing](#-contributing)
82
+
83
+ ---
84
+
85
+ ## First Queue
86
+
87
+ ```javascript
88
+ import { Queen } from 'queen-mq';
89
+
90
+ const client = new Queen({
91
+ baseUrls: ['http://localhost:6632']
92
+ });
93
+
94
+ // Configure queue
95
+ await client.queue('tasks', {
96
+ leaseTime: 300,
97
+ retryLimit: 3
98
+ });
99
+
100
+ // Push a message
101
+ await client.push('tasks', {
102
+ action: 'send-email',
103
+ to: 'user@example.com'
104
+ });
105
+
106
+ // Process messages
107
+ for await (const message of client.take('tasks')) {
108
+ console.log('Processing:', message.data);
109
+ await client.ack(message);
110
+ }
111
+ ```
112
+
113
+ That's it! You now have a working message queue system.
31
114
 
32
115
  ## ๐Ÿƒ Quick Start
33
116
 
34
117
  ### Prerequisites
35
118
 
36
- - Node.js 22+
37
- - PostgreSQL 12+
119
+ - **Node.js 22+**
120
+ - **PostgreSQL 12+**
38
121
 
39
122
  ### Installation
40
123
 
@@ -47,556 +130,1001 @@ cd queen
47
130
  nvm use 22
48
131
  npm install
49
132
 
50
- # Set up environment (optional)
133
+ # Initialize database schema
134
+ node init-db.js
135
+ ```
136
+
137
+ ### Set Environment (Optional)
138
+
139
+ ```bash
140
+ # Database connection
51
141
  export PG_USER=postgres
52
142
  export PG_HOST=localhost
53
143
  export PG_DB=postgres
54
144
  export PG_PASSWORD=postgres
55
145
  export PG_PORT=5432
146
+
147
+ # Enable encryption (optional)
148
+ export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
56
149
  ```
57
150
 
58
- ### Database Setup
151
+ ### Start the Server
59
152
 
60
153
  ```bash
61
- # Initialize the database schema
62
- node init-db.js
154
+ npm start
155
+ # Server starts on http://localhost:6632
63
156
  ```
64
157
 
65
- ### Start the Server
158
+ ---
66
159
 
67
- ```bash
68
- # Optional: Enable encryption
69
- export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
160
+ ## ๐Ÿ’ป Client Examples
70
161
 
71
- # Start the Queen server
72
- npm start
73
- # Or use the startup script
74
- ./start.sh
162
+ The Queen client provides a minimalist API with just 4 methods that compose into any messaging pattern you need.
75
163
 
76
- # Server starts on http://localhost:6632
164
+ ### Installation
165
+
166
+ ```bash
167
+ npm install queen-mq
77
168
  ```
78
169
 
79
170
  ### Basic Usage
80
171
 
172
+ #### 1. Configure a Queue
173
+
81
174
  ```javascript
82
- import { createQueenClient } from '@dev.smartpricing/queen'
175
+ import { Queen } from 'queen-mq';
83
176
 
84
- const client = createQueenClient({
85
- baseUrl: 'http://localhost:6632'
177
+ const client = new Queen({
178
+ baseUrls: ['http://localhost:6632'],
179
+ timeout: 30000,
180
+ retryAttempts: 3
86
181
  });
87
182
 
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
- }]
183
+ // Configure with options
184
+ await client.queue('orders', {
185
+ priority: 10, // Higher priority queues processed first
186
+ leaseTime: 600, // 10 minutes to process each message
187
+ retryLimit: 3, // Retry up to 3 times
188
+ delayedProcessing: 0, // No delay (immediate processing)
95
189
  });
96
190
 
97
- // Pop and process messages
98
- const result = await client.pop({
99
- queue: 'email-queue',
100
- batch: 10,
101
- wait: true
191
+ // Configure with namespace and task for grouping
192
+ await client.queue('order-processing', {
193
+ priority: 10
194
+ }, {
195
+ namespace: 'ecommerce',
196
+ task: 'checkout'
102
197
  });
103
-
104
- for (const message of result.messages) {
105
- console.log('Processing:', message.data);
106
- await client.ack(message.transactionId, 'completed');
107
- }
108
198
  ```
109
199
 
110
- ## ๐Ÿ—๏ธ Architecture
200
+ #### 2. Push Messages
111
201
 
112
- ### System Overview
202
+ ```javascript
203
+ // Single message
204
+ await client.push('orders', {
205
+ orderId: 12345,
206
+ amount: 99.99
207
+ });
113
208
 
114
- ```
115
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
116
- โ”‚ Client SDK โ”‚โ”€โ”€โ”€โ–ถโ”‚ Queen Server โ”‚โ”€โ”€โ”€โ–ถโ”‚ PostgreSQL โ”‚
117
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
118
- โ”‚
119
- โ–ผ
120
- โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
121
- โ”‚ Dashboard UI โ”‚
122
- โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
123
- ```
209
+ // To a specific partition
210
+ await client.push('orders/urgent', {
211
+ orderId: 12346,
212
+ amount: 999.99,
213
+ priority: 'high'
214
+ });
124
215
 
125
- ### Data Model
216
+ // Batch messages
217
+ await client.push('orders', [
218
+ { orderId: 12347, amount: 49.99 },
219
+ { orderId: 12348, amount: 79.99 },
220
+ { orderId: 12349, amount: 29.99 }
221
+ ]);
126
222
 
127
- ```
128
- Queues (with optional namespace/task grouping)
129
- โ””โ”€โ”€ Partitions (FIFO ordering, priority-based selection)
130
- โ””โ”€โ”€ Messages (lease-based processing)
223
+ // With message properties
224
+ await client.push('orders', {
225
+ orderId: 12350,
226
+ amount: 199.99
227
+ }, {
228
+ transactionId: 'txn-12350', // For idempotency
229
+ traceId: '550e8400-e29b-41d4-a716-446655440000' // Valid UUID for tracing
230
+ });
131
231
  ```
132
232
 
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
233
+ #### 3. Take Messages (Async Iterator)
137
234
 
138
- ### Key Components
235
+ ```javascript
236
+ // Process continuously with long polling
237
+ for await (const message of client.take('orders', {
238
+ wait: true, // Enable long polling
239
+ timeout: 30000, // 30 second timeout
240
+ batch: 10 // Fetch up to 10 at once
241
+ })) {
242
+ try {
243
+ await processOrder(message.data);
244
+ await client.ack(message); // Success
245
+ } catch (error) {
246
+ await client.ack(message, false, { error: error.message }); // Failure
247
+ }
248
+ }
139
249
 
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
250
+ // Process limited messages
251
+ for await (const message of client.take('orders', { limit: 100 })) {
252
+ await processOrder(message.data);
253
+ await client.ack(message);
254
+ }
145
255
 
146
- ## ๐Ÿ’ก Core Concepts
256
+ // Take from specific partition
257
+ for await (const message of client.take('orders/urgent')) {
258
+ await processUrgentOrder(message.data);
259
+ await client.ack(message);
260
+ }
147
261
 
148
- ### Queues and Partitions
262
+ // Use takeBatch to get arrays of messages (higher throughput)
263
+ for await (const messages of client.takeBatch('orders', {
264
+ batch: 1000, // Fetch 1000 at a time
265
+ wait: true
266
+ })) {
267
+ // messages is an array of up to 1000 messages
268
+ console.log(`Processing batch of ${messages.length} messages`);
269
+
270
+ try {
271
+ // Process entire batch
272
+ await processBatch(messages.map(m => m.data));
273
+
274
+ // Acknowledge entire batch at once (efficient!)
275
+ await client.ack(messages); // Pass array for batch ack
276
+ } catch (error) {
277
+ // Mark entire batch as failed
278
+ await client.ack(messages, false, { error: error.message });
279
+ }
280
+ }
281
+ ```
149
282
 
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.
283
+ #### 4. Acknowledge Messages
151
284
 
152
285
  ```javascript
153
- // Messages go to "Default" partition if not specified
154
- await client.push({
155
- items: [{ queue: 'orders', payload: { orderId: 123 } }]
156
- });
286
+ // Acknowledge success
287
+ await client.ack(message);
288
+ // or
289
+ await client.ack(message, true);
290
+
291
+ // Acknowledge failure (will retry based on retryLimit)
292
+ await client.ack(message, false);
157
293
 
158
- // Explicit partition specification
159
- await client.push({
160
- items: [{
161
- queue: 'orders',
162
- partition: 'high-priority',
163
- payload: { orderId: 456, urgent: true }
164
- }]
294
+ // Acknowledge with error context
295
+ await client.ack(message, false, {
296
+ error: 'Payment gateway timeout'
165
297
  });
166
- ```
167
298
 
168
- ### Priority Processing
299
+ // Acknowledge using transaction ID
300
+ await client.ack('4dfb0478-655b-4c91-bcd9-b7acacf0400f', true);
169
301
 
170
- The system supports two levels of priority:
302
+ // Request explicit retry
303
+ await client.ack(message, 'retry');
304
+ ```
305
+
306
+ ### Address Notation
171
307
 
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
308
+ Queen uses a simple addressing scheme that encodes queue, partition, and consumer group:
175
309
 
176
310
  ```javascript
177
- // Configure queue with priority
178
- await client.configure({
179
- queue: 'orders',
180
- options: { priority: 10 } // Higher number = higher priority
181
- });
311
+ // Basic addresses
312
+ 'orders' // Queue (Default partition)
313
+ 'orders/urgent' // Queue with specific partition
314
+ 'orders@workers' // Queue with consumer group (bus mode)
315
+ 'orders/urgent@workers' // Full address: queue + partition + group
316
+
317
+ // Namespace/task filtering (cross-queue consumption)
318
+ 'namespace:ecommerce' // All queues in namespace
319
+ 'task:checkout' // All queues with task
320
+ 'namespace:ecommerce/task:checkout' // Combined filter
321
+ 'namespace:ecommerce/task:checkout@audit' // With consumer group
182
322
  ```
183
323
 
184
- ### Message Lifecycle
324
+ ### Consumer Patterns
185
325
 
186
- ```
187
- pending โ†’ processing โ†’ completed/failed โ†’ (retry) โ†’ dead_letter
326
+ #### Continuous Processing (Long Polling)
327
+
328
+ ```javascript
329
+ // Efficient real-time processing
330
+ for await (const message of client.take('tasks', {
331
+ wait: true, // Long polling - waits for messages
332
+ timeout: 30000 // Server timeout
333
+ })) {
334
+ await processTask(message.data);
335
+ await client.ack(message);
336
+ }
188
337
  ```
189
338
 
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
339
+ #### Batch Processing
195
340
 
196
- ### Lease-Based Processing
341
+ ```javascript
342
+ // Method 1: Manual batching with take()
343
+ const batch = [];
344
+ for await (const message of client.take('analytics', { batch: 100 })) {
345
+ batch.push(message);
346
+
347
+ if (batch.length >= 100) {
348
+ await processBatch(batch.map(m => m.data));
349
+
350
+ // Acknowledge all
351
+ for (const msg of batch) {
352
+ await client.ack(msg);
353
+ }
354
+ batch.length = 0;
355
+ }
356
+ }
357
+
358
+ // Method 2: Direct batch processing with takeBatch() (RECOMMENDED)
359
+ for await (const messages of client.takeBatch('analytics', { batch: 1000 })) {
360
+ // messages is already an array!
361
+ await processBatch(messages.map(m => m.data));
362
+
363
+ // Single batch acknowledgment (much faster!)
364
+ await client.ack(messages);
365
+ }
366
+ ```
197
367
 
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.
368
+ #### Parallel Processing with Partitions
199
369
 
200
370
  ```javascript
201
- // Configure lease time (default: 300 seconds)
202
- await client.configure({
203
- queue: 'long-tasks',
204
- options: { leaseTime: 600 } // 10 minutes
205
- });
206
- ```
371
+ // Create workers for parallel processing
372
+ const partitions = ['worker-1', 'worker-2', 'worker-3', 'worker-4'];
207
373
 
208
- ## ๐Ÿ” Advanced Concepts
374
+ // Distribute messages across partitions
375
+ for (let i = 0; i < messages.length; i++) {
376
+ const partition = partitions[i % partitions.length];
377
+ await client.push(`tasks/${partition}`, messages[i]);
378
+ }
209
379
 
210
- ### Partition Locking
380
+ // Each worker processes its own partition (in parallel)
381
+ async function worker(partition) {
382
+ for await (const msg of client.take(`tasks/${partition}`)) {
383
+ await processTask(msg.data);
384
+ await client.ack(msg);
385
+ }
386
+ }
387
+
388
+ // Start all workers
389
+ await Promise.all(partitions.map(p => worker(p)));
390
+ ```
391
+
392
+ #### Consumer Groups (Bus Mode)
211
393
 
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.
394
+ ```javascript
395
+ // Multiple services process the same messages independently
213
396
 
214
- #### How Partition Locking Works
397
+ // Analytics service
398
+ for await (const event of client.take('events@analytics')) {
399
+ await updateAnalytics(event.data);
400
+ await client.ack(event, true, { group: 'analytics' });
401
+ }
215
402
 
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`
403
+ // Monitoring service (gets same messages)
404
+ for await (const event of client.take('events@monitoring')) {
405
+ await checkThresholds(event.data);
406
+ await client.ack(event, true, { group: 'monitoring' });
407
+ }
220
408
 
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
409
+ // Audit service (also gets same messages)
410
+ for await (const event of client.take('events@audit')) {
411
+ await logToAudit(event.data);
412
+ await client.ack(event, true, { group: 'audit' });
413
+ }
414
+ ```
225
415
 
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
416
+ #### Subscription Modes
229
417
 
230
418
  ```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
419
+ // Start from all existing messages (replay)
420
+ for await (const event of client.take('events@replay-service', {
421
+ subscriptionMode: 'all'
422
+ })) {
423
+ await replayEvent(event.data);
424
+ await client.ack(event);
425
+ }
234
426
 
235
- const consumer2 = await client.pop({ queue: 'orders' });
236
- // Consumer 2 gets messages from partition B (A is locked)
427
+ // Start from new messages only (real-time)
428
+ for await (const event of client.take('events@realtime', {
429
+ subscriptionMode: 'new'
430
+ })) {
431
+ await processEvent(event.data);
432
+ await client.ack(event);
433
+ }
237
434
 
238
- // After Consumer 1 acknowledges:
239
- await client.ack(consumer1.messages[0].transactionId, 'completed');
240
- // Partition A is now unlocked and available
435
+ // Start from specific timestamp
436
+ for await (const event of client.take('events@historical', {
437
+ subscriptionMode: 'from',
438
+ subscriptionFrom: '2024-01-01T00:00:00Z'
439
+ })) {
440
+ await processHistoricalEvent(event.data);
441
+ await client.ack(event);
442
+ }
241
443
  ```
242
444
 
243
- ### FIFO Ordering Guarantees
244
-
245
- Queen provides strong FIFO (First-In-First-Out) ordering guarantees **within each partition**. This means:
445
+ #### Error Handling
246
446
 
247
- #### Partition-Level FIFO
447
+ ```javascript
448
+ // Robust error handling with retries
449
+ for await (const message of client.take('critical-tasks')) {
450
+ let retries = 3;
451
+
452
+ while (retries > 0) {
453
+ try {
454
+ await processTask(message.data);
455
+ await client.ack(message);
456
+ break;
457
+ } catch (error) {
458
+ retries--;
459
+ if (retries === 0) {
460
+ console.error('Task failed after retries:', error);
461
+ await client.ack(message, false, { error: error.message });
462
+ } else {
463
+ await new Promise(r => setTimeout(r, 1000 * (4 - retries)));
464
+ }
465
+ }
466
+ }
467
+ }
468
+ ```
248
469
 
249
- Messages within the same partition are always processed in the exact order they were received:
470
+ #### Graceful Shutdown
250
471
 
251
472
  ```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
- ]
473
+ let running = true;
474
+
475
+ process.on('SIGTERM', () => {
476
+ console.log('Shutting down gracefully...');
477
+ running = false;
259
478
  });
260
479
 
261
- // Consumer will always receive them in order 1, 2, 3
262
- const result = await client.pop({ queue: 'tasks', partition: 'user-123' });
480
+ for await (const message of client.take('orders')) {
481
+ if (!running) break;
482
+
483
+ await processOrder(message.data);
484
+ await client.ack(message);
485
+ }
486
+
487
+ await client.close();
488
+ console.log('Shutdown complete');
263
489
  ```
264
490
 
265
- #### Cross-Partition Ordering
491
+ ---
266
492
 
267
- Messages in different partitions can be processed in parallel and have no ordering guarantees relative to each other:
493
+ ## ๐Ÿ–ฅ๏ธ Server Setup
268
494
 
269
- ```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
- });
277
- ```
495
+ ### Single Server
278
496
 
279
- #### Use Cases for Partitioning
497
+ ```bash
498
+ # Start the server
499
+ npm start
280
500
 
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
501
+ # Or with custom configuration
502
+ PORT=6632 \
503
+ DB_POOL_SIZE=20 \
504
+ QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32) \
505
+ npm start
506
+ ```
284
507
 
285
- ### Consumer Groups (Bus Mode)
508
+ ### Multi-Server (Load Balanced)
286
509
 
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.
510
+ Queen supports running multiple servers for high availability and load distribution:
288
511
 
289
- #### How Consumer Groups Work
512
+ ```bash
513
+ # Server 1
514
+ PORT=6632 WORKER_ID=server-1 npm start
290
515
 
291
- 1. **Independent Processing**: Each consumer group maintains its own:
292
- - Message status tracking
293
- - Partition leases
294
- - Retry counters
295
- - Processing state
516
+ # Server 2
517
+ PORT=6633 WORKER_ID=server-2 npm start
296
518
 
297
- 2. **Message Visibility**: All consumer groups see all messages, but each group tracks which messages it has processed independently
519
+ # Server 3
520
+ PORT=6634 WORKER_ID=server-3 npm start
521
+ ```
298
522
 
299
- 3. **Partition Locking per Group**: Within a consumer group, partition locking still applies to prevent duplicate processing
523
+ Client configuration:
300
524
 
301
525
  ```javascript
302
- // Analytics service (Group A)
303
- const analyticsResult = await client.pop({
304
- queue: 'events',
305
- consumerGroup: 'analytics-service'
526
+ const client = new Queen({
527
+ baseUrls: [
528
+ 'http://localhost:6632',
529
+ 'http://localhost:6633',
530
+ 'http://localhost:6634'
531
+ ],
532
+ loadBalancingStrategy: 'ROUND_ROBIN', // or 'RANDOM', 'LEAST_CONNECTIONS'
533
+ enableFailover: true
306
534
  });
535
+ ```
307
536
 
308
- // Audit service (Group B) - gets the same messages
309
- const auditResult = await client.pop({
310
- queue: 'events',
311
- consumerGroup: 'audit-service'
312
- });
537
+ ### Docker Deployment
313
538
 
314
- // Billing service (Group C) - also gets the same messages
315
- const billingResult = await client.pop({
316
- queue: 'events',
317
- consumerGroup: 'billing-service'
318
- });
539
+ ```dockerfile
540
+ FROM node:22-alpine
541
+
542
+ WORKDIR /app
543
+ COPY package*.json ./
544
+ RUN npm ci --production
545
+
546
+ COPY . .
547
+
548
+ EXPOSE 6632
549
+ CMD ["node", "src/server.js"]
319
550
  ```
320
551
 
321
- #### Consumer Group Subscription Modes
552
+ ```yaml
553
+ # docker-compose.yml
554
+ version: '3.8'
322
555
 
323
- When a consumer group is created, it can specify when to start consuming messages:
556
+ services:
557
+ postgres:
558
+ image: postgres:16
559
+ environment:
560
+ POSTGRES_DB: queen
561
+ POSTGRES_USER: queen
562
+ POSTGRES_PASSWORD: queen
563
+ volumes:
564
+ - postgres_data:/var/lib/postgresql/data
565
+ ports:
566
+ - "5432:5432"
324
567
 
325
- ```javascript
326
- // Start from all existing messages
327
- await client.pop({
328
- queue: 'events',
329
- consumerGroup: 'replay-service',
330
- subscriptionMode: 'all'
331
- });
568
+ queen:
569
+ build: .
570
+ ports:
571
+ - "6632:6632"
572
+ environment:
573
+ PG_HOST: postgres
574
+ PG_DB: queen
575
+ PG_USER: queen
576
+ PG_PASSWORD: queen
577
+ DB_POOL_SIZE: 20
578
+ QUEEN_ENCRYPTION_KEY: ${QUEEN_ENCRYPTION_KEY}
579
+ depends_on:
580
+ - postgres
332
581
 
333
- // Start from messages created after joining
334
- await client.pop({
335
- queue: 'events',
336
- consumerGroup: 'realtime-service',
337
- subscriptionMode: 'new'
338
- });
582
+ volumes:
583
+ postgres_data:
584
+ ```
339
585
 
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
- });
586
+ ### Environment Variables
587
+
588
+ See the [Configuration](#-configuration) section for a complete list of environment variables.
589
+
590
+ ### Database Schema
591
+
592
+ The database schema is automatically created when you run:
593
+
594
+ ```bash
595
+ node init-db.js
346
596
  ```
347
597
 
348
- ### Namespace and Task Filtering
598
+ This creates:
599
+ - `queen.queues` - Top-level message containers
600
+ - `queen.partitions` - Subdivisions within queues (FIFO ordering)
601
+ - `queen.messages` - Individual messages with processing state
602
+
603
+ ---
604
+
605
+ ## ๐Ÿ’ก Core Concepts
606
+
607
+ ### Architecture
608
+
609
+ Queen uses a two-tier architecture:
349
610
 
350
- Queen supports cross-queue message consumption through namespace and task filtering, with full partition locking support:
611
+ ```
612
+ Queues (optional namespace/task grouping)
613
+ โ””โ”€โ”€ Partitions (FIFO ordering, parallel processing)
614
+ โ””โ”€โ”€ Messages (lease-based processing)
615
+ ```
616
+
617
+ **Key Principles:**
618
+ - **Configuration at queue level**: All settings (priority, lease time, retries) apply to the entire queue
619
+ - **FIFO within partitions**: Messages in the same partition are always processed in order
620
+ - **Partition locking**: Prevents duplicate processing across consumers
621
+ - **Lease-based processing**: Messages automatically return to pending if not acknowledged
351
622
 
352
- #### Namespace-Based Routing
623
+ ### Queues and Partitions
353
624
 
354
- Group related queues under a namespace and consume from all of them:
625
+ **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.
355
626
 
356
627
  ```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
- });
628
+ // Messages go to "Default" partition
629
+ await client.push('orders', { orderId: 123 });
364
630
 
365
- await client.configure({
366
- queue: 'inventory-updates',
367
- namespace: 'ecommerce',
368
- task: 'update',
369
- options: { leaseTime: 30 }
370
- });
631
+ // Push to specific partition
632
+ await client.push('orders/high-priority', { orderId: 456 });
371
633
 
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
634
+ // Take from specific partition
635
+ for await (const order of client.take('orders/high-priority')) {
636
+ await processUrgentOrder(order.data);
637
+ await client.ack(order);
638
+ }
377
639
  ```
378
640
 
379
- #### Task-Based Routing
641
+ **Partitions enable:**
642
+ - **Parallel processing**: Different consumers can process different partitions simultaneously
643
+ - **Ordered processing**: FIFO guarantees within each partition
644
+ - **Logical separation**: Different priorities, teams, or workflow stages
645
+ - **Resource isolation**: Lock contention is per-partition
380
646
 
381
- Filter messages by specific tasks across namespaces:
647
+ ### Message Lifecycle
382
648
 
383
- ```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
649
  ```
650
+ pending โ†’ processing โ†’ completed/failed โ†’ (retry) โ†’ dead_letter
651
+ ```
652
+
653
+ 1. **Pending**: Message queued, waiting to be processed
654
+ 2. **Processing**: Leased to a worker (with timeout)
655
+ 3. **Completed**: Successfully processed
656
+ 4. **Failed**: Processing failed (may retry based on `retryLimit`)
657
+ 5. **Dead Letter**: Exceeded retry limits
390
658
 
391
- #### Partition Locking with Filters
659
+ ### Partition Locking
660
+
661
+ **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:
392
662
 
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
663
+ - The consumer acknowledges all messages (releases lock)
664
+ - The lease expires (automatic release)
665
+ - The consumer explicitly releases the partition
666
+
667
+ **Lock Scope:**
668
+ - **Queue Mode**: Each consumer session is unique - locks prevent any other consumer from accessing the partition
669
+ - **Bus Mode**: Locks are per consumer group - different groups can process the same partition independently
397
670
 
398
671
  ```javascript
399
- // Consumer 1: Gets messages and locks partitions A, B, C
400
- const result1 = await client.pop({ namespace: 'ecommerce' });
672
+ // Example: Partition locking in action
401
673
 
402
- // Consumer 2: Gets messages from different partitions D, E (A, B, C are locked)
403
- const result2 = await client.pop({ namespace: 'ecommerce' });
674
+ // Consumer 1 takes from partition A (locks it)
675
+ for await (const msg of client.take('orders', { limit: 5 })) {
676
+ // Processing partition A - no other consumer can access it
677
+ await client.ack(msg);
678
+ // Partition A unlocked after all 5 messages acknowledged
679
+ }
404
680
 
405
- // No partition overlap between consumers
681
+ // Consumer 2 gets messages from partition B (A was locked)
682
+ for await (const msg of client.take('orders', { limit: 5 })) {
683
+ // Processing partition B instead
684
+ await client.ack(msg);
685
+ }
406
686
  ```
407
687
 
408
- ### Concurrency Control
688
+ ### FIFO Ordering
689
+
690
+ Queen provides **strong FIFO guarantees within each partition**:
691
+
692
+ ```javascript
693
+ // These messages will be processed in order 1, 2, 3
694
+ await client.push('tasks/user-123', [
695
+ { step: 1, action: 'create' },
696
+ { step: 2, action: 'update' },
697
+ { step: 3, action: 'complete' }
698
+ ]);
699
+
700
+ // Consumer will always receive them in order
701
+ for await (const task of client.take('tasks/user-123')) {
702
+ console.log(task.data.step); // Prints: 1, then 2, then 3
703
+ await client.ack(task);
704
+ }
705
+ ```
409
706
 
410
- Queen provides several mechanisms for controlling concurrent message processing:
707
+ **Use cases:**
708
+ - **Per-user operations**: Use user ID as partition for ordered processing
709
+ - **Per-resource operations**: Use resource ID to maintain operation order
710
+ - **Workflow stages**: Use partition to represent different stages
411
711
 
412
- #### 1. Partition-Based Concurrency
712
+ ### Consumer Groups (Bus Mode)
413
713
 
414
- Control parallelism by the number of partitions:
714
+ Consumer groups enable **pub-sub messaging** where multiple independent consumers process the same messages:
415
715
 
416
716
  ```javascript
417
- // Create multiple partitions for parallel processing
418
- const partitions = ['worker-1', 'worker-2', 'worker-3', 'worker-4'];
717
+ // Push once
718
+ await client.push('events', { type: 'order.created', orderId: 123 });
719
+
720
+ // Multiple services consume independently
721
+ // Service 1: Analytics
722
+ for await (const event of client.take('events@analytics')) {
723
+ await updateAnalytics(event.data);
724
+ await client.ack(event);
725
+ }
419
726
 
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
- }))
427
- });
727
+ // Service 2: Notification (gets same message)
728
+ for await (const event of client.take('events@notification')) {
729
+ await sendNotification(event.data);
730
+ await client.ack(event);
731
+ }
428
732
 
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
733
+ // Service 3: Audit (also gets same message)
734
+ for await (const event of client.take('events@audit')) {
735
+ await logEvent(event.data);
736
+ await client.ack(event);
737
+ }
433
738
  ```
434
739
 
435
- #### 2. Lease-Based Concurrency
740
+ **Each consumer group maintains:**
741
+ - Independent message status tracking
742
+ - Separate partition leases
743
+ - Individual retry counters
744
+ - Isolated processing state
436
745
 
437
- Automatic concurrency control through lease timeouts:
746
+ ### Queue Mode vs Bus Mode
438
747
 
748
+ **Queue Mode** (default - competitive consumption):
439
749
  ```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
- }
447
- });
750
+ // Without consumer group - messages distributed
751
+ await client.push('tasks', { id: 1 });
752
+ await client.push('tasks', { id: 2 });
448
753
 
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
- }
456
- });
754
+ // Worker 1 gets message 1
755
+ for await (const msg of client.take('tasks')) { }
756
+
757
+ // Worker 2 gets message 2 (different message)
758
+ for await (const msg of client.take('tasks')) { }
457
759
  ```
458
760
 
459
- #### 3. Batch Size Control
761
+ **Bus Mode** (pub-sub with consumer groups):
762
+ ```javascript
763
+ // With consumer groups - all groups see all messages
764
+ await client.push('events', { id: 1 });
765
+
766
+ // Group 1 gets message 1
767
+ for await (const msg of client.take('events@group1')) { }
460
768
 
461
- Limit concurrent processing per consumer:
769
+ // Group 2 also gets message 1 (same message)
770
+ for await (const msg of client.take('events@group2')) { }
771
+ ```
462
772
 
773
+ **Mixed Mode** (combine both):
463
774
  ```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
469
- });
775
+ // Competitive workers process jobs
776
+ for await (const job of client.take('jobs')) {
777
+ await processJob(job.data);
778
+ await client.ack(job);
779
+ }
470
780
 
471
- // Process batch
472
- for (const message of batch.messages) {
473
- await processMessage(message);
474
- await client.ack(message.transactionId, 'completed');
781
+ // Monitoring sees all jobs (bus mode)
782
+ for await (const job of client.take('jobs@monitoring')) {
783
+ await monitorJob(job.data);
784
+ await client.ack(job);
475
785
  }
476
786
  ```
477
787
 
478
- ### Message Visibility and Isolation
479
-
480
- #### Queue Mode (Default)
788
+ ### Priority Processing
481
789
 
482
- In queue mode, messages are consumed competitively - once a consumer gets a message, no other consumer can see it:
790
+ Configure priority at the **queue level**:
483
791
 
484
792
  ```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
793
+ await client.queue('urgent-orders', { priority: 100 });
794
+ await client.queue('normal-orders', { priority: 50 });
795
+ await client.queue('batch-jobs', { priority: 10 });
796
+
797
+ // Urgent orders processed first, then normal, then batch
489
798
  ```
490
799
 
491
- #### Bus Mode (Consumer Groups)
800
+ ### Lease-Based Processing
492
801
 
493
- In bus mode, all consumer groups see all messages:
802
+ Messages are "leased" to workers for a specific duration. If not acknowledged within the lease time, they automatically return to pending status:
494
803
 
495
804
  ```javascript
496
- // With consumer groups - broadcast consumption
497
- const service1 = await client.pop({
498
- queue: 'events',
499
- consumerGroup: 'service-1'
805
+ // Configure lease time
806
+ await client.queue('long-tasks', {
807
+ leaseTime: 600 // 10 minutes to process
500
808
  });
501
809
 
502
- const service2 = await client.pop({
503
- queue: 'events',
504
- consumerGroup: 'service-2'
505
- });
506
- // Both services get the same messages
810
+ // If worker crashes or takes too long:
811
+ // - After 10 minutes, lease expires
812
+ // - Message returns to pending
813
+ // - Another worker can pick it up
507
814
  ```
508
815
 
509
- #### Mixed Mode
816
+ ### Delayed Processing
510
817
 
511
- You can combine both patterns in the same system:
818
+ Schedule messages for future processing:
512
819
 
513
820
  ```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'
821
+ await client.queue('scheduled-jobs', {
822
+ delayedProcessing: 3600 // 1 hour delay
521
823
  });
522
824
 
523
- const analytics = await client.pop({
524
- queue: 'jobs',
525
- consumerGroup: 'analytics'
825
+ await client.push('scheduled-jobs', {
826
+ reportType: 'daily-sales'
526
827
  });
828
+ // Message won't be available for processing until 1 hour later
527
829
  ```
528
830
 
529
- ### Best Practices
831
+ ### Window Buffering
530
832
 
531
- #### 1. Partition Strategy
833
+ Batch messages within a time window:
532
834
 
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
835
+ ```javascript
836
+ await client.queue('analytics', {
837
+ windowBuffer: 60 // Wait 60 seconds to accumulate messages
838
+ });
537
839
 
538
- #### 2. Consumer Group Design
840
+ // Messages held for 60 seconds to allow efficient batching
841
+ ```
539
842
 
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
843
+ ### Retry and Dead Letter Queue
543
844
 
544
- #### 3. Lease Management
845
+ ```javascript
846
+ await client.queue('payments', {
847
+ retryLimit: 3, // Retry up to 3 times
848
+ dlqAfterMaxRetries: true // Move to DLQ after max retries
849
+ });
545
850
 
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
851
+ // Failed messages automatically retry
852
+ await client.ack(message, false); // Will retry if retries < 3
549
853
 
550
- #### 4. Error Handling
854
+ // After 3 failures, message moves to dead_letter status
855
+ ```
551
856
 
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);
857
+ ### Enterprise Features
858
+
859
+ #### 1. Encryption (AES-256-GCM)
860
+
861
+ ```bash
862
+ # Generate encryption key
863
+ export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
864
+ ```
865
+
866
+ ```javascript
867
+ await client.queue('sensitive-data', {
868
+ encryptionEnabled: true
869
+ });
870
+
871
+ // Messages encrypted at rest in database
872
+ await client.push('sensitive-data', { ssn: '123-45-6789' });
873
+ ```
874
+
875
+ #### 2. Message Retention
876
+
877
+ ```javascript
878
+ await client.queue('temp-queue', {
879
+ retentionSeconds: 3600, // Delete pending after 1 hour
880
+ completedRetentionSeconds: 300, // Delete completed after 5 minutes
881
+ retentionEnabled: true
882
+ });
883
+ ```
884
+
885
+ #### 3. Message Eviction (SLA Enforcement)
886
+
887
+ ```javascript
888
+ await client.queue('time-sensitive', {
889
+ maxWaitTimeSeconds: 60 // Evict messages older than 1 minute
890
+ });
891
+ ```
892
+
893
+ ### Best Practices
894
+
895
+ **1. Partition Strategy**
896
+ - Use user IDs for per-user ordering
897
+ - Use resource IDs for per-resource ordering
898
+ - Use round-robin for load distribution
899
+ - Keep partition counts manageable (10-100s, not 1000s)
900
+
901
+ **2. Lease Management**
902
+ - Set lease time slightly longer than expected processing time
903
+ - Handle timeouts gracefully
904
+ - Acknowledge messages as soon as processing completes
905
+
906
+ **3. Consumer Group Design**
907
+ - One clear purpose per consumer group
908
+ - Design groups to be independent
909
+ - Ensure operations are idempotent
910
+
911
+ **4. Error Handling**
912
+ - Always wrap processing in try-catch
913
+ - Provide meaningful error messages in ack
914
+ - Use retry limits appropriately
915
+ - Monitor dead letter queue
916
+
917
+ ---
918
+
919
+ ## ๐Ÿš€ Cursor-Based Consumption Strategy
920
+
921
+ Queen uses a **cursor-based consumption model** for optimal performance at scale, providing O(batch_size) constant-time operations regardless of queue depth.
922
+
923
+ ### How It Works
924
+
925
+ Traditional message queues scan through all messages to find pending ones, leading to performance degradation as messages accumulate. Queen's cursor-based approach maintains a position marker (cursor) for each consumer, allowing direct access to the next batch of messages.
926
+
927
+ **Partition Cursors:**
928
+
929
+ Each partition maintains a cursor position per consumer group:
930
+ - `last_consumed_created_at`: Timestamp of last consumed message
931
+ - `last_consumed_id`: UUID of last consumed message (tie-breaker for same timestamp)
932
+ - `total_messages_consumed`: Running count of consumed messages
933
+
934
+ The cursor always moves **forward** in time, ensuring strict FIFO ordering.
935
+
936
+ ### The takeBatch Method
937
+
938
+ Queen provides two consumption methods:
939
+
940
+ **1. `take()` - Individual message iterator:**
941
+ ```javascript
942
+ // Processes messages one at a time
943
+ for await (const message of client.take('orders', { batch: 1000 })) {
944
+ await processOrder(message.data);
945
+ await client.ack(message);
568
946
  }
569
947
  ```
570
948
 
571
- ## ๐Ÿ”Œ API Reference
949
+ **2. `takeBatch()` - Array iterator (HIGH PERFORMANCE):**
950
+ ```javascript
951
+ // Yields arrays of messages - achieves 100k+ msg/s throughput
952
+ for await (const messages of client.takeBatch('orders', { batch: 1000 })) {
953
+ // messages is an array of up to 1000 message objects
954
+ await processBatch(messages.map(m => m.data));
955
+
956
+ // Batch acknowledge - single DB transaction for all messages
957
+ await client.ack(messages);
958
+ }
959
+ ```
960
+
961
+ **Under the hood**, both methods use cursor-based batch retrieval:
962
+
963
+ ```sql
964
+ -- Cursor-based query (simplified)
965
+ SELECT * FROM messages
966
+ WHERE partition_id = $1
967
+ AND id > $2::uuid -- Start after last cursor position
968
+ ORDER BY created_at ASC, id ASC
969
+ LIMIT $3 -- Batch size
970
+ FOR UPDATE SKIP LOCKED
971
+ ```
972
+
973
+ **Key characteristics:**
974
+ 1. **Constant-time**: Performance stays consistent whether you've consumed 0% or 99% of messages
975
+ 2. **FIFO guarantee**: Messages always returned in creation order
976
+ 3. **Lock-free scanning**: `SKIP LOCKED` prevents contention between consumers
977
+ 4. **Efficient**: No table scans - direct cursor-based access using UUIDv7 (time-ordered)
978
+
979
+ **Performance tip:** Use `takeBatch()` with large batch sizes (1,000-10,000) for maximum throughput. The server fetches messages in batches regardless, but `takeBatch()` gives you the array directly, allowing bulk processing and batch acknowledgment in a single operation.
980
+
981
+ ### Batch Acknowledgment Semantics
982
+
983
+ Queen handles batch acknowledgments intelligently:
984
+
985
+ **Partial Success** (some messages succeed, some fail):
986
+ ```javascript
987
+ // Batch: 10,000 messages
988
+ // Success: 9,999 messages
989
+ // Failed: 1 message
990
+
991
+ // Behavior:
992
+ // โœ… Cursor advances past all 10,000 messages
993
+ // โœ… Failed message moved to Dead Letter Queue
994
+ // โœ… Next take() starts from message 10,001
995
+ // โœ… FIFO maintained, no redelivery of successful messages
996
+ ```
997
+
998
+ **Total Batch Failure** (all messages fail):
999
+ ```javascript
1000
+ // Batch: 10,000 messages
1001
+ // Success: 0 messages
1002
+ // Failed: 10,000 messages
1003
+
1004
+ // Behavior:
1005
+ // โŒ Cursor DOES NOT advance
1006
+ // โŒ Messages NOT moved to DLQ
1007
+ // โœ… Lease released
1008
+ // โœ… Next take() gets SAME batch (retry)
1009
+ // โœ… Allows recovery from transient failures
1010
+ ```
1011
+
1012
+ This design handles transient failures (network issues, service outages) gracefully while preventing poison messages from blocking the queue.
1013
+
1014
+ ### Performance Comparison
572
1015
 
573
- ### Base URL
1016
+ | Operation | Traditional Approach | Cursor Approach | Improvement |
1017
+ |-----------|---------------------|-----------------|-------------|
1018
+ | Pop @ 0% consumed | O(partition_size) | O(batch_size) | Same |
1019
+ | Pop @ 50% consumed | O(partition_size) | O(batch_size) | **10-100x faster** |
1020
+ | Pop @ 99% consumed | O(partition_size) | O(batch_size) | **100-1000x faster** |
1021
+
1022
+ **Real-world benchmark** (1M messages):
1023
+ ```
1024
+ Traditional:
1025
+ Early batches: 300ms per pop
1026
+ Late batches: 3500ms per pop (10x degradation)
1027
+
1028
+ Cursor-based:
1029
+ Early batches: 150ms per pop
1030
+ Late batches: 200ms per pop (constant!)
574
1031
  ```
575
- http://localhost:6632/api/v1
1032
+
1033
+ ### Dead Letter Queue
1034
+
1035
+ Individual message failures are moved to the Dead Letter Queue for inspection and manual intervention:
1036
+
1037
+ ```javascript
1038
+ // Monitor DLQ
1039
+ const response = await fetch('http://localhost:6632/api/v1/analytics/dlq');
1040
+ const dlqMessages = await response.json();
1041
+
1042
+ // Inspect failed messages
1043
+ for (const msg of dlqMessages) {
1044
+ console.log(`Failed: ${msg.error_message}`);
1045
+
1046
+ // After fixing issue, can re-push if needed
1047
+ await client.push(msg.queue, fixedPayload);
1048
+ }
1049
+ ```
1050
+
1051
+ **DLQ Query:**
1052
+ ```sql
1053
+ SELECT * FROM queen.dead_letter_queue
1054
+ WHERE consumer_group = 'my-group'
1055
+ ORDER BY failed_at DESC
1056
+ LIMIT 100;
1057
+ ```
1058
+
1059
+ ### Batch Size Guidelines
1060
+
1061
+ Choose batch sizes based on your workload:
1062
+
1063
+ **Smaller batches (100-1,000):**
1064
+ - โœ… Faster individual batch processing
1065
+ - โœ… Less impact if entire batch fails
1066
+ - โœ… Lower memory footprint
1067
+ - โŒ More network round-trips
1068
+
1069
+ **Larger batches (5,000-10,000):**
1070
+ - โœ… Higher throughput (100,000+ msg/sec achievable)
1071
+ - โœ… Fewer network round-trips
1072
+ - โœ… Better database efficiency
1073
+ - โŒ More messages retry if entire batch fails
1074
+ - โŒ Higher memory usage
1075
+
1076
+ **Recommendation:** Start with 1,000-2,000 for balanced performance. Increase to 5,000-10,000 for maximum throughput with reliable processing.
1077
+
1078
+ ### Monitoring Cursor Progress
1079
+
1080
+ Track consumption progress via SQL:
1081
+
1082
+ ```sql
1083
+ -- View cursor positions
1084
+ SELECT
1085
+ p.name as partition,
1086
+ pc.consumer_group,
1087
+ pc.total_messages_consumed,
1088
+ pc.total_batches_consumed,
1089
+ pc.last_consumed_at,
1090
+ EXTRACT(EPOCH FROM (NOW() - pc.last_consumed_at)) as seconds_since_last_consume
1091
+ FROM queen.partition_cursors pc
1092
+ JOIN queen.partitions p ON p.id = pc.partition_id
1093
+ ORDER BY pc.last_consumed_at DESC;
1094
+
1095
+ -- Monitor DLQ
1096
+ SELECT COUNT(*) as failed_count, consumer_group
1097
+ FROM queen.dead_letter_queue
1098
+ GROUP BY consumer_group;
576
1099
  ```
577
1100
 
1101
+ ---
1102
+
1103
+ ## ๐Ÿ”Œ HTTP API Reference
1104
+
1105
+ Base URL: `http://localhost:6632/api/v1`
1106
+
578
1107
  ### Push Messages
579
1108
 
580
1109
  **Endpoint:** `POST /api/v1/push`
581
1110
 
582
- ```javascript
1111
+ **Request:**
1112
+ ```json
583
1113
  {
584
1114
  "items": [
585
1115
  {
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
1116
+ "queue": "orders",
1117
+ "partition": "urgent",
1118
+ "payload": { "orderId": 123, "amount": 99.99 },
1119
+ "transactionId": "optional-idempotency-key",
1120
+ "traceId": "550e8400-e29b-41d4-a716-446655440000"
593
1121
  }
594
1122
  ]
595
1123
  }
596
1124
  ```
597
1125
 
598
1126
  **Response:**
599
- ```javascript
1127
+ ```json
600
1128
  {
601
1129
  "messages": [
602
1130
  {
@@ -610,35 +1138,40 @@ http://localhost:6632/api/v1
610
1138
 
611
1139
  ### Pop Messages
612
1140
 
613
- **From Specific Partition:**
1141
+ **From specific partition:**
614
1142
  ```
615
1143
  GET /api/v1/pop/queue/{queue}/partition/{partition}?wait=true&timeout=30000&batch=10
616
1144
  ```
617
1145
 
618
- **From Any Partition in Queue:**
1146
+ **From any partition in queue:**
619
1147
  ```
620
1148
  GET /api/v1/pop/queue/{queue}?wait=true&timeout=30000&batch=10
621
1149
  ```
622
1150
 
623
- **With Namespace/Task Filter:**
1151
+ **With namespace/task filter:**
624
1152
  ```
625
- GET /api/v1/pop?namespace=my-app&task=emails&wait=true&timeout=30000&batch=10
1153
+ GET /api/v1/pop?namespace=ecommerce&task=checkout&wait=true&timeout=30000&batch=10
1154
+ ```
1155
+
1156
+ **With consumer group (bus mode):**
1157
+ ```
1158
+ GET /api/v1/pop/queue/{queue}?consumerGroup=analytics&subscriptionMode=all&wait=true&timeout=30000
626
1159
  ```
627
1160
 
628
1161
  **Response:**
629
- ```javascript
1162
+ ```json
630
1163
  {
631
1164
  "messages": [
632
1165
  {
633
1166
  "id": "018e63b7-6165-453f-88ae-56effa177605",
634
1167
  "transactionId": "4dfb0478-655b-4c91-bcd9-b7acacf0400f",
635
- "queue": "email-queue",
1168
+ "queue": "orders",
636
1169
  "partition": "urgent",
637
- "data": { "to": "user@example.com", "subject": "Hello" },
1170
+ "data": { "orderId": 123, "amount": 99.99 },
638
1171
  "retryCount": 0,
639
1172
  "priority": 10,
640
- "createdAt": "2023-10-08T12:00:00.000Z",
641
- "options": { "leaseTime": 300 }
1173
+ "createdAt": "2024-10-08T12:00:00.000Z",
1174
+ "options": { "leaseTime": 300, "retryLimit": 3 }
642
1175
  }
643
1176
  ]
644
1177
  }
@@ -646,850 +1179,971 @@ GET /api/v1/pop?namespace=my-app&task=emails&wait=true&timeout=30000&batch=10
646
1179
 
647
1180
  ### Acknowledge Messages
648
1181
 
649
- **Single Acknowledgment:**
650
- ```javascript
1182
+ **Single:**
1183
+ ```json
651
1184
  POST /api/v1/ack
652
1185
  {
653
- "transactionId": "uuid",
654
- "status": "completed", // "completed" or "failed"
655
- "error": "optional error" // Required if status is "failed"
1186
+ "transactionId": "4dfb0478-655b-4c91-bcd9-b7acacf0400f",
1187
+ "status": "completed",
1188
+ "consumerGroup": "analytics",
1189
+ "error": null
656
1190
  }
657
1191
  ```
658
1192
 
659
- **Batch Acknowledgment:**
660
- ```javascript
1193
+ **Batch:**
1194
+ ```json
661
1195
  POST /api/v1/ack/batch
662
1196
  {
663
1197
  "acknowledgments": [
664
- { "transactionId": "uuid1", "status": "completed" },
665
- { "transactionId": "uuid2", "status": "failed", "error": "Processing error" }
1198
+ { "transactionId": "uuid-1", "status": "completed" },
1199
+ { "transactionId": "uuid-2", "status": "failed", "error": "Processing error" }
666
1200
  ]
667
1201
  }
668
1202
  ```
669
1203
 
670
- ### Queue Configuration
1204
+ ### Configure Queue
671
1205
 
672
- ```javascript
1206
+ ```json
673
1207
  POST /api/v1/configure
674
1208
  {
675
- "queue": "email-queue",
676
- "partition": "urgent", // Optional (defaults to "Default")
1209
+ "queue": "orders",
1210
+ "namespace": "ecommerce",
1211
+ "task": "checkout",
677
1212
  "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
1213
+ "leaseTime": 600,
1214
+ "retryLimit": 5,
1215
+ "priority": 10,
1216
+ "maxSize": 10000,
1217
+ "ttl": 3600,
1218
+ "dlqAfterMaxRetries": true,
1219
+ "delayedProcessing": 0,
1220
+ "windowBuffer": 0,
1221
+ "retentionSeconds": 0,
1222
+ "completedRetentionSeconds": 0,
1223
+ "retentionEnabled": false,
1224
+ "encryptionEnabled": false,
1225
+ "maxWaitTimeSeconds": 0
683
1226
  }
684
1227
  }
685
1228
  ```
686
1229
 
687
1230
  ### Analytics
688
1231
 
689
- ```javascript
690
- // Get all queues overview
691
- GET /api/v1/analytics/queues
1232
+ **Queue statistics:**
1233
+ ```
1234
+ GET /api/v1/analytics/queue/{queue}
1235
+ ```
692
1236
 
693
- // Get queue statistics
694
- GET /api/v1/analytics/queue/{queueName}
1237
+ **All queues overview:**
1238
+ ```
1239
+ GET /api/v1/analytics/queues
1240
+ ```
695
1241
 
696
- // Get namespace statistics
697
- GET /api/v1/analytics?namespace={namespace}
1242
+ **Queue depths:**
1243
+ ```
1244
+ GET /api/v1/analytics/queue-depths
1245
+ ```
698
1246
 
699
- // Get throughput metrics
1247
+ **Throughput metrics:**
1248
+ ```
700
1249
  GET /api/v1/analytics/throughput
1250
+ ```
701
1251
 
702
- // Get queue depths
703
- GET /api/v1/analytics/queue-depths
1252
+ **Queue lag analysis:**
1253
+ ```
1254
+ GET /api/v1/analytics/queue-lag?queue=orders
704
1255
  ```
705
1256
 
706
- ## ๐Ÿ“ฑ Client SDK
1257
+ ### Message Management
707
1258
 
708
- ### Installation
1259
+ **List messages:**
1260
+ ```
1261
+ GET /api/v1/messages?queue=orders&status=pending&limit=100
1262
+ ```
709
1263
 
710
- ```javascript
711
- import { createQueenClient } from './src/client/queenClient.js';
1264
+ **Get single message:**
1265
+ ```
1266
+ GET /api/v1/messages/{transactionId}
1267
+ ```
712
1268
 
713
- const client = createQueenClient({
714
- baseUrl: 'http://localhost:6632',
715
- timeout: 30000,
716
- retryAttempts: 3,
717
- retryDelay: 1000
718
- });
1269
+ **Delete message:**
1270
+ ```
1271
+ DELETE /api/v1/messages/{transactionId}
1272
+ ```
1273
+
1274
+ **Retry failed message:**
1275
+ ```
1276
+ POST /api/v1/messages/{transactionId}/retry
1277
+ ```
1278
+
1279
+ **Move to dead letter queue:**
1280
+ ```
1281
+ POST /api/v1/messages/{transactionId}/dlq
1282
+ ```
1283
+
1284
+ **Clear queue:**
1285
+ ```
1286
+ DELETE /api/v1/queues/{queue}/clear
1287
+ ```
1288
+
1289
+ **Delete queue:**
1290
+ ```
1291
+ DELETE /api/v1/resources/queues/{queue}
1292
+ ```
1293
+ _Note: Deletes the queue and all its partitions, messages, and related data._
1294
+
1295
+ ### System Health
1296
+
1297
+ **Health check:**
1298
+ ```
1299
+ GET /health
1300
+ ```
1301
+
1302
+ **Detailed metrics:**
1303
+ ```
1304
+ GET /metrics
719
1305
  ```
720
1306
 
721
- ### Basic Operations
1307
+ ### WebSocket (Real-time Updates)
722
1308
 
1309
+ **Connect:**
723
1310
  ```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
- });
1311
+ const ws = new WebSocket('ws://localhost:6632/ws/dashboard');
733
1312
 
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
- });
1313
+ ws.onmessage = (event) => {
1314
+ const { event: eventType, data } = JSON.parse(event.data);
1315
+ // Handle events: message.pushed, message.completed, queue.depth, etc.
1316
+ };
1317
+ ```
742
1318
 
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
- });
1319
+ **Events:**
1320
+ - `message.pushed` - New message added
1321
+ - `message.processing` - Message being processed
1322
+ - `message.completed` - Message completed
1323
+ - `message.failed` - Message failed
1324
+ - `queue.created` - New queue created
1325
+ - `queue.depth` - Queue depth update (every 5s)
1326
+ - `system.stats` - System statistics (every 10s)
751
1327
 
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
- });
1328
+ See [API.md](API.md) for complete API documentation.
759
1329
 
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
- }
1330
+ ---
1331
+
1332
+ ## ๐Ÿ“Š Dashboard
1333
+
1334
+ Queen includes a comprehensive web dashboard for monitoring and management.
1335
+
1336
+ [Dashboard](/assets/dashboard-01.png)
1337
+
1338
+ ### Access
1339
+
1340
+ 1. Start the server: `npm start`
1341
+ 2. Open browser: `http://localhost:4000`
1342
+ 3. WebSocket connection provides real-time updates
1343
+
1344
+ ### Features
1345
+
1346
+ **System Overview**
1347
+ - Real-time metrics: total messages, processing rate, system health
1348
+ - Queue summary with pending/processing/completed counts
1349
+ - Performance indicators: throughput, latency, error rates
1350
+
1351
+ **Queue Management**
1352
+ - Queue list with status and message counts
1353
+ - Partition view with priority indicators
1354
+ - Message browser with search and filter
1355
+ - Retry and DLQ management
1356
+
1357
+ **Real-time Monitoring**
1358
+ - Live updates via WebSocket
1359
+ - Throughput charts (messages per second over time)
1360
+ - Queue depth graphs with trend analysis
1361
+ - Lag monitoring (processing time and backlog)
1362
+
1363
+ **Analytics Dashboard**
1364
+ - Performance metrics per queue
1365
+ - Historical trends and patterns
1366
+ - System health monitoring
1367
+ - Database connections and memory usage
1368
+
1369
+ **Message Browser**
1370
+ - Search by queue, partition, status, time range
1371
+ - View full payload and metadata
1372
+ - Manually retry failed messages
1373
+ - Dead letter queue management
1374
+
1375
+ ### Dashboard Development
1376
+
1377
+ The dashboard is built with Vue.js and located in the `dashboard/` directory:
1378
+
1379
+ ```bash
1380
+ cd dashboard
1381
+ npm install
1382
+ npm run dev # Development mode
1383
+ npm run build # Production build
769
1384
  ```
770
1385
 
771
- ### Consumer Pattern
1386
+ ---
772
1387
 
773
- The SDK provides a convenient consumer helper for continuous message processing with two modes:
1388
+ ## โš™๏ธ Configuration
774
1389
 
775
- #### Individual Message Processing
1390
+ All configuration uses environment variables with sensible defaults. Configuration is centralized in `src/config.js`.
776
1391
 
777
- Process messages one by one (default behavior):
1392
+ ### Server Configuration
778
1393
 
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
- });
1394
+ ```bash
1395
+ PORT=6632 # Server port (default: 6632)
1396
+ HOST=0.0.0.0 # Server host (default: 0.0.0.0)
1397
+ WORKER_ID=worker-1 # Worker identifier
1398
+ APP_NAME=queen-mq # Application name
795
1399
 
796
- // Stop the consumer when needed
797
- // stopConsumer();
1400
+ # CORS
1401
+ CORS_MAX_AGE=86400
1402
+ CORS_ALLOWED_ORIGINS=*
1403
+ CORS_ALLOWED_METHODS=GET,POST,PUT,DELETE,OPTIONS
1404
+ CORS_ALLOWED_HEADERS=Content-Type,Authorization
798
1405
  ```
799
1406
 
800
- #### Batch Message Processing
1407
+ ### Database Configuration
801
1408
 
802
- Process entire batches of messages at once for better performance:
1409
+ ```bash
1410
+ # Connection
1411
+ PG_USER=postgres
1412
+ PG_HOST=localhost
1413
+ PG_DB=postgres
1414
+ PG_PASSWORD=postgres
1415
+ PG_PORT=5432
803
1416
 
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
- });
1417
+ # Connection pool
1418
+ DB_POOL_SIZE=20 # Max connections
1419
+ DB_IDLE_TIMEOUT=30000 # Idle timeout (ms)
1420
+ DB_CONNECTION_TIMEOUT=2000 # Connection timeout (ms)
1421
+ DB_STATEMENT_TIMEOUT=30000 # Statement timeout (ms)
1422
+ DB_QUERY_TIMEOUT=30000 # Query timeout (ms)
1423
+ DB_MAX_RETRIES=3 # Max retry attempts
831
1424
  ```
832
1425
 
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
1426
+ ### Queue Processing
838
1427
 
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)
1428
+ ```bash
1429
+ # Pop defaults
1430
+ DEFAULT_TIMEOUT=30000 # Default pop timeout (ms)
1431
+ MAX_TIMEOUT=60000 # Maximum pop timeout (ms)
1432
+ DEFAULT_BATCH_SIZE=1 # Default batch size
1433
+ BATCH_INSERT_SIZE=1000 # Batch size for bulk inserts
843
1434
 
844
- ### Advanced Features
1435
+ # Long polling
1436
+ QUEUE_POLL_INTERVAL=100 # Poll interval (ms)
1437
+ QUEUE_POLL_INTERVAL_FILTERED=1000 # Poll interval for filtered pops (ms)
845
1438
 
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
- });
1439
+ # Queue defaults
1440
+ DEFAULT_LEASE_TIME=300 # Lease time (seconds)
1441
+ DEFAULT_RETRY_LIMIT=3 # Retry limit
1442
+ DEFAULT_RETRY_DELAY=1000 # Retry delay (ms)
1443
+ DEFAULT_MAX_SIZE=10000 # Max queue size
1444
+ DEFAULT_TTL=3600 # TTL (seconds)
1445
+ DEFAULT_PRIORITY=0 # Priority
1446
+ DEFAULT_DELAYED_PROCESSING=0 # Delayed processing (seconds)
1447
+ DEFAULT_WINDOW_BUFFER=0 # Window buffer (seconds)
1448
+ ```
853
1449
 
854
- // Batch acknowledgment
855
- await client.ackBatch([
856
- { transactionId: 'uuid1', status: 'completed' },
857
- { transactionId: 'uuid2', status: 'failed', error: 'Invalid data' }
858
- ]);
1450
+ ### Background Jobs
859
1451
 
860
- // Message management
861
- const messages = await client.messages.list({
862
- queue: 'orders',
863
- status: 'failed',
864
- limit: 100
865
- });
1452
+ ```bash
1453
+ LEASE_RECLAIM_INTERVAL=5000 # Lease reclamation (ms)
1454
+ RETENTION_INTERVAL=300000 # Retention checks (ms)
1455
+ RETENTION_BATCH_SIZE=1000 # Retention batch size
1456
+ PARTITION_CLEANUP_DAYS=7 # Days before cleaning empty partitions
1457
+ EVICTION_INTERVAL=60000 # Eviction checks (ms)
1458
+ EVICTION_BATCH_SIZE=1000 # Eviction batch size
1459
+ ```
866
1460
 
867
- await client.messages.retry('transaction-id');
868
- await client.messages.moveToDLQ('transaction-id');
1461
+ ### WebSocket
1462
+
1463
+ ```bash
1464
+ WS_COMPRESSION=0 # Compression level
1465
+ WS_MAX_PAYLOAD_LENGTH=16384 # Max payload (bytes)
1466
+ WS_IDLE_TIMEOUT=60 # Idle timeout (seconds)
1467
+ WS_MAX_CONNECTIONS=1000 # Max connections
1468
+ WS_HEARTBEAT_INTERVAL=30000 # Heartbeat (ms)
869
1469
  ```
870
1470
 
871
- ## ๐Ÿ“Š Dashboard
1471
+ ### Encryption
872
1472
 
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:
1473
+ ```bash
1474
+ # Generate key: openssl rand -hex 32
1475
+ QUEEN_ENCRYPTION_KEY=<64-hex-chars> # AES-256-GCM encryption key
1476
+ ```
951
1477
 
952
- ```javascript
953
- // Connect to dashboard WebSocket
954
- const ws = new WebSocket('ws://localhost:6632/ws/dashboard');
1478
+ ### Client SDK
955
1479
 
956
- // Receive real-time updates
957
- ws.onmessage = (event) => {
958
- const { event: eventType, data } = JSON.parse(event.data);
1480
+ ```bash
1481
+ QUEEN_BASE_URL=http://localhost:6632
1482
+ CLIENT_RETRY_ATTEMPTS=3
1483
+ CLIENT_RETRY_DELAY=1000
1484
+ CLIENT_RETRY_BACKOFF=2
1485
+ CLIENT_POOL_SIZE=10
1486
+ CLIENT_REQUEST_TIMEOUT=30000
1487
+ ```
1488
+
1489
+ ### Queue Options
1490
+
1491
+ ```javascript
1492
+ {
1493
+ // Processing
1494
+ leaseTime: 300, // Seconds before lease expires
1495
+ retryLimit: 3, // Max retry attempts
1496
+ priority: 0, // Queue priority (higher = first)
1497
+ delayedProcessing: 0, // Delay in seconds
1498
+ windowBuffer: 0, // Buffer time for batching
1499
+ dlqAfterMaxRetries: true, // Move to DLQ after max retries
959
1500
 
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
- };
1501
+ // Encryption (Queue-level)
1502
+ encryptionEnabled: false, // Enable AES-256-GCM encryption
1503
+
1504
+ // Retention (Partition-level)
1505
+ retentionSeconds: 0, // Delete pending messages after X seconds
1506
+ completedRetentionSeconds: 0, // Delete completed/failed after X seconds
1507
+ partitionRetentionSeconds: 0, // Delete empty partitions after X seconds
1508
+ retentionEnabled: false, // Enable retention
1509
+
1510
+ // Eviction (Queue-level)
1511
+ maxWaitTimeSeconds: 0 // Evict messages older than X seconds
1512
+ }
972
1513
  ```
973
1514
 
974
- ## ๐Ÿ“š Examples
1515
+ ---
1516
+
1517
+ ## ๐Ÿ“š Full Examples
975
1518
 
976
- ### Basic Email Queue
1519
+ ### Example 1: Email Queue with Priority
977
1520
 
978
1521
  ```javascript
979
- // Configure email queue with priority
980
- await client.configure({
981
- queue: 'emails-urgent',
982
- options: { priority: 10, leaseTime: 300 }
983
- });
1522
+ import { Queen } from 'queen-mq';
984
1523
 
985
- await client.configure({
986
- queue: 'emails-normal',
987
- options: { priority: 5, leaseTime: 300 }
1524
+ const client = new Queen({
1525
+ baseUrls: ['http://localhost:6632']
988
1526
  });
989
1527
 
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
- }]
1528
+ // Configure queues with different priorities
1529
+ await client.queue('emails-urgent', {
1530
+ priority: 10,
1531
+ leaseTime: 300,
1532
+ retryLimit: 5
1001
1533
  });
1002
1534
 
1003
- // Process emails (urgent emails processed first)
1004
- const result = await client.pop({
1005
- queue: 'emails',
1006
- batch: 10,
1007
- wait: true
1535
+ await client.queue('emails-normal', {
1536
+ priority: 5,
1537
+ leaseTime: 300,
1538
+ retryLimit: 3
1008
1539
  });
1540
+
1541
+ // Producer: Send emails
1542
+ async function sendEmails() {
1543
+ // Urgent email
1544
+ await client.push('emails-urgent', {
1545
+ to: 'admin@company.com',
1546
+ subject: 'Critical Alert',
1547
+ body: 'System issue detected',
1548
+ timestamp: Date.now()
1549
+ });
1550
+
1551
+ // Normal email
1552
+ await client.push('emails-normal', {
1553
+ to: 'user@example.com',
1554
+ subject: 'Welcome',
1555
+ body: 'Thanks for signing up',
1556
+ timestamp: Date.now()
1557
+ });
1558
+ }
1559
+
1560
+ // Consumer: Process emails
1561
+ async function processEmails() {
1562
+ // Urgent emails processed first (higher priority)
1563
+ for await (const email of client.take('emails-urgent', {
1564
+ wait: true,
1565
+ timeout: 30000
1566
+ })) {
1567
+ try {
1568
+ console.log('Sending urgent email:', email.data.to);
1569
+ await sendEmail(email.data);
1570
+ await client.ack(email);
1571
+ } catch (error) {
1572
+ console.error('Failed to send email:', error);
1573
+ await client.ack(email, false, { error: error.message });
1574
+ }
1575
+ }
1576
+ }
1577
+
1578
+ // Send batch of emails
1579
+ await sendEmails();
1580
+
1581
+ // Start processing
1582
+ processEmails().catch(console.error);
1009
1583
  ```
1010
1584
 
1011
- ### Delayed Job Processing
1585
+ ### Example 2: Task Pipeline
1012
1586
 
1013
1587
  ```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
- }
1588
+ import { Queen } from 'queen-mq';
1589
+
1590
+ const client = new Queen({
1591
+ baseUrls: ['http://localhost:6632']
1021
1592
  });
1022
1593
 
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']
1594
+ // Configure pipeline stages
1595
+ await client.queue('stage-1-validate', { priority: 10 });
1596
+ await client.queue('stage-2-process', { priority: 9 });
1597
+ await client.queue('stage-3-finalize', { priority: 8 });
1598
+
1599
+ // Stage 1: Validate
1600
+ async function validateStage() {
1601
+ for await (const msg of client.take('stage-1-validate', { wait: true })) {
1602
+ try {
1603
+ const validated = await validate(msg.data);
1604
+ await client.ack(msg);
1605
+
1606
+ // Pass to next stage
1607
+ await client.push('stage-2-process', validated);
1608
+ } catch (error) {
1609
+ await client.ack(msg, false, { error: error.message });
1032
1610
  }
1033
- }]
1034
- });
1611
+ }
1612
+ }
1035
1613
 
1036
- // Job will not be available for processing until 1 hour later
1614
+ // Stage 2: Process
1615
+ async function processStage() {
1616
+ for await (const msg of client.take('stage-2-process', { wait: true })) {
1617
+ try {
1618
+ const processed = await process(msg.data);
1619
+ await client.ack(msg);
1620
+
1621
+ // Pass to next stage
1622
+ await client.push('stage-3-finalize', processed);
1623
+ } catch (error) {
1624
+ await client.ack(msg, false, { error: error.message });
1625
+ }
1626
+ }
1627
+ }
1628
+
1629
+ // Stage 3: Finalize
1630
+ async function finalizeStage() {
1631
+ for await (const msg of client.take('stage-3-finalize', { wait: true })) {
1632
+ try {
1633
+ await finalize(msg.data);
1634
+ await client.ack(msg);
1635
+ console.log('Pipeline complete:', msg.data.id);
1636
+ } catch (error) {
1637
+ await client.ack(msg, false, { error: error.message });
1638
+ }
1639
+ }
1640
+ }
1641
+
1642
+ // Start pipeline
1643
+ Promise.all([
1644
+ validateStage(),
1645
+ processStage(),
1646
+ finalizeStage()
1647
+ ]);
1648
+
1649
+ // Add work to pipeline
1650
+ await client.push('stage-1-validate', { id: 1, data: 'raw data' });
1037
1651
  ```
1038
1652
 
1039
- ### Batch Processing with Window Buffer
1653
+ ### Example 3: Event Streaming (Bus Mode)
1040
1654
 
1041
1655
  ```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
- }
1656
+ import { Queen } from 'queen-mq';
1657
+
1658
+ const client = new Queen({
1659
+ baseUrls: ['http://localhost:6632']
1049
1660
  });
1050
1661
 
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
- }]
1662
+ // Configure event queue
1663
+ await client.queue('events', {
1664
+ priority: 10,
1665
+ leaseTime: 60
1666
+ });
1667
+
1668
+ // Producer: Emit events
1669
+ async function emitEvents() {
1670
+ await client.push('events', {
1671
+ type: 'order.created',
1672
+ orderId: 12345,
1673
+ userId: 789,
1674
+ amount: 99.99,
1675
+ timestamp: Date.now()
1059
1676
  });
1060
1677
  }
1061
1678
 
1062
- // Messages will be held for 60 seconds to allow batching
1063
- // Then all messages become available at once for efficient processing
1064
- ```
1679
+ // Consumer 1: Analytics Service
1680
+ async function analyticsService() {
1681
+ for await (const event of client.take('events@analytics', {
1682
+ subscriptionMode: 'all', // Replay all messages
1683
+ wait: true
1684
+ })) {
1685
+ console.log('[Analytics] Processing event:', event.data.type);
1686
+ await updateAnalytics(event.data);
1687
+ await client.ack(event, true, { group: 'analytics' });
1688
+ }
1689
+ }
1065
1690
 
1066
- ### Multi-Queue Processing with Priorities
1691
+ // Consumer 2: Notification Service
1692
+ async function notificationService() {
1693
+ for await (const event of client.take('events@notifications', {
1694
+ subscriptionMode: 'new', // Only new messages
1695
+ wait: true
1696
+ })) {
1697
+ console.log('[Notifications] Processing event:', event.data.type);
1698
+ await sendNotification(event.data);
1699
+ await client.ack(event, true, { group: 'notifications' });
1700
+ }
1701
+ }
1067
1702
 
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 }
1080
- });
1703
+ // Consumer 3: Audit Service
1704
+ async function auditService() {
1705
+ for await (const event of client.take('events@audit', {
1706
+ subscriptionMode: 'all', // Log everything
1707
+ wait: true
1708
+ })) {
1709
+ console.log('[Audit] Logging event:', event.data.type);
1710
+ await logToAudit(event.data);
1711
+ await client.ack(event, true, { group: 'audit' });
1712
+ }
1081
1713
  }
1082
1714
 
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
- });
1715
+ // Start all services (they all see the same events)
1716
+ Promise.all([
1717
+ analyticsService(),
1718
+ notificationService(),
1719
+ auditService()
1720
+ ]);
1721
+
1722
+ // Emit events
1723
+ await emitEvents();
1092
1724
  ```
1093
1725
 
1094
- ### High-Throughput Batch Processing
1726
+ ### Example 4: Batch Processing (High Throughput)
1095
1727
 
1096
1728
  ```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
- }
1729
+ import { Queen } from 'queen-mq';
1730
+
1731
+ const client = new Queen({
1732
+ baseUrls: ['http://localhost:6632']
1105
1733
  });
1106
1734
 
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
-
1735
+ // Configure for batch processing
1736
+ await client.queue('data-processing', {
1737
+ priority: 5,
1738
+ leaseTime: 600, // 10 minutes for batch
1739
+ windowBuffer: 30 // Buffer for 30 seconds
1740
+ });
1741
+
1742
+ // Producer: Send data
1743
+ async function sendData() {
1744
+ const records = [];
1745
+ for (let i = 0; i < 100000; i++) {
1746
+ records.push({ id: i, value: Math.random() });
1747
+ }
1748
+
1749
+ // Push in batches
1750
+ await client.push('data-processing/analytics', records);
1751
+ }
1752
+
1753
+ // Consumer: HIGH PERFORMANCE batch processor using takeBatch()
1754
+ async function batchProcessor() {
1755
+ const BATCH_SIZE = 5000; // Large batches for 100k+ msg/s throughput
1756
+
1757
+ // takeBatch() yields arrays directly - no manual batching needed!
1758
+ for await (const messages of client.takeBatch('data-processing/analytics', {
1759
+ batch: BATCH_SIZE,
1760
+ wait: true,
1761
+ timeout: 30000
1762
+ })) {
1115
1763
  try {
1116
- // Extract all payloads for batch processing
1117
- const events = messages.map(msg => ({
1118
- id: msg.transactionId,
1119
- ...msg.data
1120
- }));
1764
+ console.log(`Processing batch of ${messages.length} records`);
1765
+
1766
+ // Extract data
1767
+ const records = messages.map(m => m.data);
1121
1768
 
1122
- // Process entire batch efficiently
1123
- await processAnalyticsBatch(events);
1769
+ // Bulk process (single DB operation)
1770
+ await bulkInsertToDatabase(records);
1124
1771
 
1125
- const processingTime = Date.now() - startTime;
1126
- console.log(`โœ… Batch processed in ${processingTime}ms`);
1772
+ // Batch acknowledge (single DB transaction!)
1773
+ await client.ack(messages);
1127
1774
 
1775
+ console.log(`โœ“ Batch complete in single transaction`);
1128
1776
  } catch (error) {
1129
1777
  console.error('Batch processing failed:', error);
1130
- throw error; // Will mark all messages as failed
1778
+
1779
+ // Mark entire batch as failed (single transaction)
1780
+ await client.ack(messages, false, { error: error.message });
1131
1781
  }
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
1782
  }
1139
- });
1140
-
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);
1150
1783
  }
1784
+
1785
+ // Run
1786
+ await sendData();
1787
+ await batchProcessor();
1788
+
1789
+ // Performance characteristics:
1790
+ // - Batch size 5000: ~100,000 messages/second
1791
+ // - Single DB transaction per batch (fetch + ack)
1792
+ // - Constant memory usage
1793
+ // - No performance degradation as queue grows
1151
1794
  ```
1152
1795
 
1153
- ## โšก Performance
1796
+ ### Example 5: Scheduled Jobs
1154
1797
 
1155
- ### Benchmarks
1798
+ ```javascript
1799
+ import { Queen } from 'queen-mq';
1156
1800
 
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
1801
+ const client = new Queen({
1802
+ baseUrls: ['http://localhost:6632']
1803
+ });
1161
1804
 
1162
- ### Optimization Features
1805
+ // Configure with delayed processing
1806
+ await client.queue('scheduled-jobs', {
1807
+ delayedProcessing: 3600, // 1 hour delay
1808
+ priority: 5
1809
+ });
1163
1810
 
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
1811
+ // Schedule a job
1812
+ async function scheduleReport() {
1813
+ await client.push('scheduled-jobs/daily-reports', {
1814
+ reportType: 'daily-sales',
1815
+ date: new Date().toISOString().split('T')[0],
1816
+ recipients: ['manager@company.com'],
1817
+ scheduledAt: Date.now()
1818
+ });
1819
+
1820
+ console.log('Report scheduled for processing in 1 hour');
1821
+ }
1169
1822
 
1170
- ### Performance Tuning
1823
+ // Process scheduled jobs
1824
+ async function processScheduledJobs() {
1825
+ for await (const job of client.take('scheduled-jobs/daily-reports', {
1826
+ wait: true
1827
+ })) {
1828
+ try {
1829
+ console.log('Generating report:', job.data.reportType);
1830
+ await generateReport(job.data);
1831
+ await client.ack(job);
1832
+ } catch (error) {
1833
+ await client.ack(job, false, { error: error.message });
1834
+ }
1835
+ }
1836
+ }
1171
1837
 
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
1838
+ await scheduleReport();
1839
+ processScheduledJobs().catch(console.error);
1177
1840
  ```
1178
1841
 
1179
- ## ๐Ÿ”’ Enterprise Features
1180
-
1181
- Queen includes three powerful enterprise features for production deployments:
1842
+ ### Example 6: Rate Limiting
1182
1843
 
1183
- ### 1. Encryption
1184
- Protect sensitive data with AES-256-GCM encryption at the queue level.
1844
+ ```javascript
1845
+ import { Queen } from 'queen-mq';
1185
1846
 
1186
- **Setup:**
1187
- ```bash
1188
- # Set encryption key (64 hex characters = 32 bytes)
1189
- export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
1190
- ```
1847
+ const client = new Queen({
1848
+ baseUrls: ['http://localhost:6632']
1849
+ });
1191
1850
 
1192
- **Configuration:**
1193
- ```javascript
1194
- await client.configure({
1195
- queue: 'sensitive-data',
1196
- options: {
1197
- encryptionEnabled: true
1198
- }
1851
+ await client.queue('api-calls', {
1852
+ priority: 5,
1853
+ leaseTime: 60
1199
1854
  });
1200
- ```
1201
1855
 
1202
- ### 2. Message Retention
1203
- Automatically clean up old messages to prevent storage bloat.
1856
+ // Producer: Queue API calls
1857
+ async function queueApiCalls(calls) {
1858
+ await client.push('api-calls', calls);
1859
+ }
1204
1860
 
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
1861
+ // Consumer: Rate-limited processor (10 calls per second max)
1862
+ async function rateLimitedProcessor() {
1863
+ const RATE_LIMIT = 10; // calls per second
1864
+ const INTERVAL = 1000; // 1 second
1865
+
1866
+ let callsThisInterval = 0;
1867
+ let intervalStart = Date.now();
1868
+
1869
+ for await (const call of client.take('api-calls', { wait: true })) {
1870
+ // Check if we need to wait
1871
+ if (callsThisInterval >= RATE_LIMIT) {
1872
+ const elapsed = Date.now() - intervalStart;
1873
+ if (elapsed < INTERVAL) {
1874
+ await new Promise(r => setTimeout(r, INTERVAL - elapsed));
1875
+ }
1876
+ callsThisInterval = 0;
1877
+ intervalStart = Date.now();
1878
+ }
1879
+
1880
+ try {
1881
+ await makeApiCall(call.data);
1882
+ await client.ack(call);
1883
+ callsThisInterval++;
1884
+ } catch (error) {
1885
+ await client.ack(call, false, { error: error.message });
1886
+ }
1213
1887
  }
1214
- });
1215
- ```
1888
+ }
1216
1889
 
1217
- **Environment:**
1218
- ```bash
1219
- export RETENTION_INTERVAL=300000 # Cleanup interval in milliseconds
1890
+ // Generate calls
1891
+ const calls = Array.from({ length: 100 }, (_, i) => ({
1892
+ id: i,
1893
+ endpoint: '/api/data',
1894
+ method: 'GET'
1895
+ }));
1896
+
1897
+ await queueApiCalls(calls);
1898
+ rateLimitedProcessor().catch(console.error);
1220
1899
  ```
1221
1900
 
1222
- ### 3. Message Eviction
1223
- Enforce SLAs by automatically evicting messages that wait too long.
1901
+ ### Example 7: Enterprise Features
1224
1902
 
1225
- **Configuration:**
1226
1903
  ```javascript
1227
- await client.configure({
1228
- queue: 'time-sensitive',
1229
- options: {
1230
- maxWaitTimeSeconds: 60 // Evict messages older than 1 minute
1231
- }
1904
+ import { Queen } from 'queen-mq';
1905
+
1906
+ const client = new Queen({
1907
+ baseUrls: ['http://localhost:6632']
1232
1908
  });
1233
- ```
1234
1909
 
1235
- **Environment:**
1236
- ```bash
1237
- export EVICTION_INTERVAL=60000 # Check interval in milliseconds
1238
- ```
1910
+ // Configure with all enterprise features
1911
+ await client.queue('production-queue', {
1912
+ // Encryption
1913
+ encryptionEnabled: true,
1914
+
1915
+ // Retention
1916
+ retentionSeconds: 86400, // Delete pending after 24 hours
1917
+ completedRetentionSeconds: 3600, // Delete completed after 1 hour
1918
+ retentionEnabled: true,
1919
+
1920
+ // Eviction (SLA enforcement)
1921
+ maxWaitTimeSeconds: 600, // Evict messages older than 10 minutes
1922
+
1923
+ // Standard options
1924
+ priority: 10,
1925
+ leaseTime: 300,
1926
+ retryLimit: 3,
1927
+ dlqAfterMaxRetries: true
1928
+ });
1239
1929
 
1240
- ### Combined Example
1241
- ```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,
1255
-
1256
- // Standard options
1257
- priority: 10,
1258
- leaseTime: 300
1259
- }
1930
+ // Push sensitive data (will be encrypted)
1931
+ await client.push('production-queue', {
1932
+ userId: 123,
1933
+ creditCard: '4111-1111-1111-1111',
1934
+ amount: 99.99,
1935
+ timestamp: Date.now()
1260
1936
  });
1937
+
1938
+ // Process (data decrypted automatically)
1939
+ for await (const message of client.take('production-queue', { wait: true })) {
1940
+ console.log('Processing encrypted data:', message.data.userId);
1941
+ await processPayment(message.data);
1942
+ await client.ack(message);
1943
+ }
1261
1944
  ```
1262
1945
 
1263
- ## โš™๏ธ Configuration
1946
+ ---
1264
1947
 
1265
- ### Environment Variables
1948
+ ## ๐Ÿงช Testing
1266
1949
 
1267
- All configuration values have sensible defaults and can be overridden using environment variables. Configuration is centralized in `src/config.js`.
1950
+ Queen includes a comprehensive test suite covering all features.
1268
1951
 
1269
- #### Server Configuration
1952
+ ### Run Tests
1270
1953
 
1271
1954
  ```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
1277
-
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
1283
- ```
1955
+ # Start the server first
1956
+ npm start
1284
1957
 
1285
- #### Database Configuration
1958
+ # Run all tests
1959
+ node src/test/test-new.js
1286
1960
 
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)
1961
+ # Run specific test categories
1962
+ node src/test/test-new.js core # Core features
1963
+ node src/test/test-new.js partition # Partition locking
1964
+ node src/test/test-new.js enterprise # Enterprise features
1965
+ node src/test/test-new.js bus # Bus mode
1966
+ node src/test/test-new.js edge # Edge cases
1967
+ node src/test/test-new.js advanced # Advanced patterns
1294
1968
 
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)
1969
+ # Show help
1970
+ node src/test/test-new.js help
1302
1971
  ```
1303
1972
 
1304
- #### Queue Processing Configuration
1305
-
1306
- ```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)
1312
-
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)
1973
+ ### Test Coverage
1316
1974
 
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)
1975
+ The test suite verifies:
1326
1976
 
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)
1977
+ **Core Features:**
1978
+ - Queue creation and configuration
1979
+ - Single and batch message push
1980
+ - Message take and acknowledgment
1981
+ - Delayed processing
1982
+ - Partition FIFO ordering
1983
+
1984
+ **Partition Locking:**
1985
+ - Lock acquisition and release
1986
+ - Bus mode partition locking
1987
+ - Specific partition locking
1988
+ - Namespace/task filtering with locking
1989
+
1990
+ **Enterprise Features:**
1991
+ - AES-256-GCM encryption
1992
+ - Message retention policies
1993
+ - Message eviction
1994
+ - Combined enterprise features
1995
+
1996
+ **Bus Mode:**
1997
+ - Consumer groups
1998
+ - Subscription modes (all, new, from)
1999
+ - Consumer group isolation
2000
+ - Mixed mode (queue + bus)
2001
+
2002
+ **Edge Cases:**
2003
+ - Empty and null payloads
2004
+ - Very large payloads
2005
+ - Concurrent operations
2006
+ - Lease expiration
2007
+ - SQL injection prevention
2008
+ - XSS prevention
2009
+
2010
+ **Advanced Patterns:**
2011
+ - Multi-stage pipelines
2012
+ - Fan-out/fan-in
2013
+ - Priority scenarios
2014
+ - Dead letter queue
2015
+ - Circuit breaker
2016
+ - Message deduplication
2017
+ - Event sourcing
1330
2018
 
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)
2019
+ ### Test Results
1335
2020
 
1336
- # Eviction
1337
- DEFAULT_MAX_WAIT_TIME_SECONDS=0 # Max wait time before eviction (default: 0 = disabled)
2021
+ Example output:
1338
2022
  ```
2023
+ ๐Ÿš€ Starting Queen Message Queue Test Suite
2024
+ Using the new minimalist Queen client interface
2025
+ ================================================================================
1339
2026
 
1340
- #### Background Jobs Configuration
2027
+ ๐Ÿ“ฆ CORE FEATURES
2028
+ ----------------------------------------
2029
+ โœ… Queue Creation Policy
2030
+ โœ… Single Message Push
2031
+ โœ… Batch Message Push
2032
+ โœ… Queue Configuration
2033
+ โœ… Take and Acknowledgment
2034
+ โœ… Delayed Processing
2035
+ โœ… Partition FIFO Ordering
1341
2036
 
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)
2037
+ ๐Ÿ”’ PARTITION LOCKING
2038
+ ----------------------------------------
2039
+ โœ… Partition Locking
2040
+ โœ… Bus Partition Locking
2041
+ โœ… Specific Partition Locking
2042
+ โœ… Namespace Task Filtering
2043
+ โœ… Namespace Task Bus Mode
1350
2044
 
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)
2045
+ ๐Ÿ“ˆ Test Summary
2046
+ ================================================================================
2047
+ Total: 42 | Passed: 42 | Failed: 0 | Duration: 45.2s
1354
2048
  ```
1355
2049
 
1356
- #### WebSocket Configuration
2050
+ ---
1357
2051
 
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)
1365
- ```
2052
+ ## ๐Ÿค Contributing
1366
2053
 
1367
- #### Encryption Configuration
2054
+ We welcome contributions! Here's how to get started:
1368
2055
 
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
- ```
2056
+ 1. **Fork the repository**
2057
+ 2. **Create a feature branch**: `git checkout -b feature/amazing-feature`
2058
+ 3. **Make your changes**
2059
+ 4. **Run the test suite**: `node src/test/test-new.js`
2060
+ 5. **Commit your changes**: `git commit -m 'Add amazing feature'`
2061
+ 6. **Push to the branch**: `git push origin feature/amazing-feature`
2062
+ 7. **Open a Pull Request**
1375
2063
 
1376
- #### Client SDK Configuration
2064
+ ### Development Setup
1377
2065
 
1378
2066
  ```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
- ```
2067
+ # Clone your fork
2068
+ git clone https://github.com/your-username/queen
2069
+ cd queen
1387
2070
 
1388
- #### API Configuration
2071
+ # Install dependencies
2072
+ nvm use 22
2073
+ npm install
1389
2074
 
1390
- ```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
- ```
2075
+ # Initialize database
2076
+ node init-db.js
1396
2077
 
1397
- #### Analytics Configuration
2078
+ # Start server
2079
+ npm start
1398
2080
 
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)
2081
+ # Run tests
2082
+ node src/test/test-new.js
1406
2083
  ```
1407
2084
 
1408
- #### Monitoring Configuration
2085
+ ### Code Style
1409
2086
 
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)
1416
- ```
2087
+ - Use ES6+ features
2088
+ - Follow existing code style
2089
+ - Add comments for complex logic
2090
+ - Write tests for new features
1417
2091
 
1418
- #### Logging Configuration
2092
+ ---
1419
2093
 
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
- ```
2094
+ ## ๐Ÿ“„ License
1427
2095
 
1428
- ### Queue Options
2096
+ Apache License 2.0 - see [LICENSE.md](LICENSE.md) for details.
1429
2097
 
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
- ```
2098
+ ---
1453
2099
 
1454
- ## ๐Ÿงช Testing
2100
+ ## ๐Ÿ”— Links
1455
2101
 
1456
- ### Run Core Feature Tests
2102
+ - **Repository**: [github.com/smartpricing/queen](https://github.com/smartpricing/queen)
2103
+ - **Documentation**: See `docs/` directory
2104
+ - **Issues**: [GitHub Issues](https://github.com/smartpricing/queen/issues)
2105
+ - **API Reference**: [API.md](API.md)
1457
2106
 
1458
- ```bash
1459
- # Start the server
1460
- npm start
2107
+ ---
1461
2108
 
1462
- # Run comprehensive test suite
1463
- node src/test/core-features-test.js
2109
+ ## ๐Ÿ“ˆ Performance
1464
2110
 
1465
- # Run full test suite (more detailed)
1466
- node src/test/comprehensive-test.js
1467
- ```
2111
+ **Benchmarks** (PostgreSQL 16, Node.js 22, cursor-based consumption):
2112
+ - **Throughput**: 100,000+ messages/second with batch operations
2113
+ - **Latency**: < 10ms for immediate pop operations
2114
+ - **Constant-time consumption**: O(batch_size) regardless of queue depth
2115
+ - **Concurrent Connections**: 1,000+ long polling connections
2116
+ - **Database**: Optimized with proper indexing and connection pooling
2117
+
2118
+ **Cursor-Based Architecture Benefits:**
2119
+ - **No performance degradation**: Consistent speed whether queue has 1K or 1B messages
2120
+ - **Predictable latency**: 150-200ms per batch throughout entire queue lifecycle
2121
+ - **Efficient batch processing**: Direct cursor access eliminates table scans
2122
+ - **Scalable to billions**: UUIDv7-based cursor positioning
2123
+
2124
+ **Additional Optimization Features:**
2125
+ - Connection pooling with configurable size
2126
+ - Resource caching for queue/partition lookups
2127
+ - Batch operations for bulk inserts/updates (up to 10,000 messages per batch)
2128
+ - Optimized SQL queries with proper indexes
2129
+ - Event-driven architecture for minimal polling overhead
2130
+ - Long polling for real-time message delivery
2131
+ - SKIP LOCKED for lock-free concurrent consumption
1468
2132
 
1469
- ### Test Results
2133
+ ---
1470
2134
 
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
2135
+ ## ๐ŸŽฏ Roadmap
1480
2136
 
1481
- ## ๐Ÿค Contributing
2137
+ - [ ] **Message Scheduling**: Cron-like scheduling for recurring jobs
2138
+ - [ ] **Client Libraries**: Python, Go, Java clients
2139
+ - [ ] **Kubernetes Operator**: Native K8s support
1482
2140
 
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
2141
+ ---
1488
2142
 
1489
- ## ๐Ÿ“„ License
2143
+ <div align="center">
1490
2144
 
1491
- MIT License - see LICENSE file for details.
2145
+ **Queen Message Queue System** - Built for performance, reliability, and developer happiness ๐Ÿš€
1492
2146
 
1493
- ---
2147
+ Made with โค๏ธ by [Smartness](https://github.com/smartpricing)
1494
2148
 
1495
- **Queen Message Queue System** - Built for performance, reliability, and scalability. ๐Ÿš€
2149
+ </div>