queen-mq 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/API.md +1116 -0
- package/CACHE.md +519 -0
- package/DASHBOARD-V3.md +478 -0
- package/DASHBOARD.md +382 -0
- package/MOD_QUEUE.md +453 -0
- package/PARTITION_LOCKING_DESIGN.md +989 -0
- package/PLAN.md +707 -0
- package/QUERY_ANALSYS.md +72 -0
- package/QUEUE_BUS.md +334 -0
- package/README.md +1495 -0
- package/V2-PLAN.md +236 -0
- package/assets/dashboard.png +0 -0
- package/dashboard/.vscode/extensions.json +3 -0
- package/dashboard/README.md +5 -0
- package/dashboard/index.html +14 -0
- package/dashboard/package-lock.json +1458 -0
- package/dashboard/package.json +25 -0
- package/dashboard/public/vite.svg +1 -0
- package/dashboard/src/App.vue +29 -0
- package/dashboard/src/assets/styles/main.css +908 -0
- package/dashboard/src/assets/vue.svg +1 -0
- package/dashboard/src/components/cards/MetricCard.vue +298 -0
- package/dashboard/src/components/charts/QueueDepthChart.vue +276 -0
- package/dashboard/src/components/charts/QueueLagChart.vue +436 -0
- package/dashboard/src/components/charts/ThroughputChart.vue +302 -0
- package/dashboard/src/components/common/ActivityFeed.vue +251 -0
- package/dashboard/src/components/layout/AppHeader.vue +208 -0
- package/dashboard/src/components/layout/AppLayout.vue +88 -0
- package/dashboard/src/components/layout/AppSidebar.vue +261 -0
- package/dashboard/src/main.js +44 -0
- package/dashboard/src/router.js +54 -0
- package/dashboard/src/services/api.js +187 -0
- package/dashboard/src/services/websocket.js +167 -0
- package/dashboard/src/utils/constants.js +56 -0
- package/dashboard/src/utils/helpers.js +118 -0
- package/dashboard/src/views/Analytics.vue +912 -0
- package/dashboard/src/views/Dashboard.vue +906 -0
- package/dashboard/src/views/Messages.vue +437 -0
- package/dashboard/src/views/QueueDetail.vue +501 -0
- package/dashboard/src/views/Queues.vue +333 -0
- package/dashboard/vite.config.js +30 -0
- package/debug-namespace.js +110 -0
- package/docs/long-polling.md +159 -0
- package/docs/multi-server-cache-solutions.md +185 -0
- package/docs/performance-tuning.md +222 -0
- package/examples/bus-mode.js +239 -0
- package/examples/continuous-consumer-optimized.js +215 -0
- package/examples/continuous-consumer.js +159 -0
- package/examples/continuous-producer.js +343 -0
- package/examples/mixed-mode.js +277 -0
- package/examples/multi-server-test.js +305 -0
- package/examples/single.js +64 -0
- package/examples/smartchat-dealyed.js +42 -0
- package/examples/smartchat.js +52 -0
- package/examples/test-cache-invalidation.js +119 -0
- package/examples/test-cache-multi-server.js +245 -0
- package/examples/test-minimal-client.js +112 -0
- package/examples/test-queue-creation-policy.js +137 -0
- package/init-db.js +20 -0
- package/package.json +36 -0
- package/src/client/client.js +291 -0
- package/src/client/index.js +6 -0
- package/src/client/queenClient.js +513 -0
- package/src/client/utils/http.js +172 -0
- package/src/client/utils/loadBalancer.js +152 -0
- package/src/client/utils/retry.js +35 -0
- package/src/config.js +215 -0
- package/src/database/connection.js +103 -0
- package/src/database/poolManager.js +192 -0
- package/src/database/schema-v2.sql +214 -0
- package/src/managers/eventManager.js +59 -0
- package/src/managers/queueManagerOptimized.js +1512 -0
- package/src/managers/resourceCache.js +96 -0
- package/src/managers/systemEventManager.js +127 -0
- package/src/routes/ack.js +26 -0
- package/src/routes/analytics.js +812 -0
- package/src/routes/configure.js +46 -0
- package/src/routes/messages.js +298 -0
- package/src/routes/pop.js +85 -0
- package/src/routes/push.js +28 -0
- package/src/routes/resources.js +296 -0
- package/src/server.js +1286 -0
- package/src/services/encryptionService.js +82 -0
- package/src/services/evictionService.js +131 -0
- package/src/services/retentionService.js +129 -0
- package/src/services/startupSync.js +35 -0
- package/src/test/test.js +4521 -0
- package/src/utils/logger.js +44 -0
- package/src/utils/uuid.js +5 -0
- package/src/websocket/wsServer.js +221 -0
package/README.md
ADDED
|
@@ -0,0 +1,1495 @@
|
|
|
1
|
+
# Queen - High-Performance Message Queue System
|
|
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.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
## ๐ Features
|
|
8
|
+
|
|
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
|
|
19
|
+
|
|
20
|
+
## ๐ Table of Contents
|
|
21
|
+
|
|
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)
|
|
31
|
+
|
|
32
|
+
## ๐ Quick Start
|
|
33
|
+
|
|
34
|
+
### Prerequisites
|
|
35
|
+
|
|
36
|
+
- Node.js 22+
|
|
37
|
+
- PostgreSQL 12+
|
|
38
|
+
|
|
39
|
+
### Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Clone the repository
|
|
43
|
+
git clone https://github.com/smartpricing/queen
|
|
44
|
+
cd queen
|
|
45
|
+
|
|
46
|
+
# Install dependencies
|
|
47
|
+
nvm use 22
|
|
48
|
+
npm install
|
|
49
|
+
|
|
50
|
+
# Set up environment (optional)
|
|
51
|
+
export PG_USER=postgres
|
|
52
|
+
export PG_HOST=localhost
|
|
53
|
+
export PG_DB=postgres
|
|
54
|
+
export PG_PASSWORD=postgres
|
|
55
|
+
export PG_PORT=5432
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Database Setup
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
# Initialize the database schema
|
|
62
|
+
node init-db.js
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Start the Server
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
# Optional: Enable encryption
|
|
69
|
+
export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
|
|
70
|
+
|
|
71
|
+
# Start the Queen server
|
|
72
|
+
npm start
|
|
73
|
+
# Or use the startup script
|
|
74
|
+
./start.sh
|
|
75
|
+
|
|
76
|
+
# Server starts on http://localhost:6632
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Basic Usage
|
|
80
|
+
|
|
81
|
+
```javascript
|
|
82
|
+
import { createQueenClient } from '@dev.smartpricing/queen'
|
|
83
|
+
|
|
84
|
+
const client = createQueenClient({
|
|
85
|
+
baseUrl: 'http://localhost:6632'
|
|
86
|
+
});
|
|
87
|
+
|
|
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
|
+
}]
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Pop and process messages
|
|
98
|
+
const result = await client.pop({
|
|
99
|
+
queue: 'email-queue',
|
|
100
|
+
batch: 10,
|
|
101
|
+
wait: true
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
for (const message of result.messages) {
|
|
105
|
+
console.log('Processing:', message.data);
|
|
106
|
+
await client.ack(message.transactionId, 'completed');
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## ๐๏ธ Architecture
|
|
111
|
+
|
|
112
|
+
### System Overview
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
|
|
116
|
+
โ Client SDK โโโโโถโ Queen Server โโโโโถโ PostgreSQL โ
|
|
117
|
+
โโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโโ โโโโโโโโโโโโโโโโโโโ
|
|
118
|
+
โ
|
|
119
|
+
โผ
|
|
120
|
+
โโโโโโโโโโโโโโโโโโโโ
|
|
121
|
+
โ Dashboard UI โ
|
|
122
|
+
โโโโโโโโโโโโโโโโโโโโ
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Data Model
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Queues (with optional namespace/task grouping)
|
|
129
|
+
โโโ Partitions (FIFO ordering, priority-based selection)
|
|
130
|
+
โโโ Messages (lease-based processing)
|
|
131
|
+
```
|
|
132
|
+
|
|
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
|
|
137
|
+
|
|
138
|
+
### Key Components
|
|
139
|
+
|
|
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
|
|
145
|
+
|
|
146
|
+
## ๐ก Core Concepts
|
|
147
|
+
|
|
148
|
+
### Queues and Partitions
|
|
149
|
+
|
|
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.
|
|
151
|
+
|
|
152
|
+
```javascript
|
|
153
|
+
// Messages go to "Default" partition if not specified
|
|
154
|
+
await client.push({
|
|
155
|
+
items: [{ queue: 'orders', payload: { orderId: 123 } }]
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Explicit partition specification
|
|
159
|
+
await client.push({
|
|
160
|
+
items: [{
|
|
161
|
+
queue: 'orders',
|
|
162
|
+
partition: 'high-priority',
|
|
163
|
+
payload: { orderId: 456, urgent: true }
|
|
164
|
+
}]
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Priority Processing
|
|
169
|
+
|
|
170
|
+
The system supports two levels of priority:
|
|
171
|
+
|
|
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
|
|
175
|
+
|
|
176
|
+
```javascript
|
|
177
|
+
// Configure queue with priority
|
|
178
|
+
await client.configure({
|
|
179
|
+
queue: 'orders',
|
|
180
|
+
options: { priority: 10 } // Higher number = higher priority
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Message Lifecycle
|
|
185
|
+
|
|
186
|
+
```
|
|
187
|
+
pending โ processing โ completed/failed โ (retry) โ dead_letter
|
|
188
|
+
```
|
|
189
|
+
|
|
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
|
|
195
|
+
|
|
196
|
+
### Lease-Based Processing
|
|
197
|
+
|
|
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.
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
// Configure lease time (default: 300 seconds)
|
|
202
|
+
await client.configure({
|
|
203
|
+
queue: 'long-tasks',
|
|
204
|
+
options: { leaseTime: 600 } // 10 minutes
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## ๐ Advanced Concepts
|
|
209
|
+
|
|
210
|
+
### Partition Locking
|
|
211
|
+
|
|
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.
|
|
213
|
+
|
|
214
|
+
#### How Partition Locking Works
|
|
215
|
+
|
|
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`
|
|
220
|
+
|
|
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
|
|
225
|
+
|
|
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
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
// Example: Two consumers in queue mode
|
|
232
|
+
const consumer1 = await client.pop({ queue: 'orders' });
|
|
233
|
+
// Consumer 1 gets messages from partition A and locks it
|
|
234
|
+
|
|
235
|
+
const consumer2 = await client.pop({ queue: 'orders' });
|
|
236
|
+
// Consumer 2 gets messages from partition B (A is locked)
|
|
237
|
+
|
|
238
|
+
// After Consumer 1 acknowledges:
|
|
239
|
+
await client.ack(consumer1.messages[0].transactionId, 'completed');
|
|
240
|
+
// Partition A is now unlocked and available
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
### FIFO Ordering Guarantees
|
|
244
|
+
|
|
245
|
+
Queen provides strong FIFO (First-In-First-Out) ordering guarantees **within each partition**. This means:
|
|
246
|
+
|
|
247
|
+
#### Partition-Level FIFO
|
|
248
|
+
|
|
249
|
+
Messages within the same partition are always processed in the exact order they were received:
|
|
250
|
+
|
|
251
|
+
```javascript
|
|
252
|
+
// These messages will be processed in order 1, 2, 3
|
|
253
|
+
await client.push({
|
|
254
|
+
items: [
|
|
255
|
+
{ queue: 'tasks', partition: 'user-123', payload: { step: 1 } },
|
|
256
|
+
{ queue: 'tasks', partition: 'user-123', payload: { step: 2 } },
|
|
257
|
+
{ queue: 'tasks', partition: 'user-123', payload: { step: 3 } }
|
|
258
|
+
]
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// Consumer will always receive them in order 1, 2, 3
|
|
262
|
+
const result = await client.pop({ queue: 'tasks', partition: 'user-123' });
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
#### Cross-Partition Ordering
|
|
266
|
+
|
|
267
|
+
Messages in different partitions can be processed in parallel and have no ordering guarantees relative to each other:
|
|
268
|
+
|
|
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
|
+
```
|
|
278
|
+
|
|
279
|
+
#### Use Cases for Partitioning
|
|
280
|
+
|
|
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
|
|
284
|
+
|
|
285
|
+
### Consumer Groups (Bus Mode)
|
|
286
|
+
|
|
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.
|
|
288
|
+
|
|
289
|
+
#### How Consumer Groups Work
|
|
290
|
+
|
|
291
|
+
1. **Independent Processing**: Each consumer group maintains its own:
|
|
292
|
+
- Message status tracking
|
|
293
|
+
- Partition leases
|
|
294
|
+
- Retry counters
|
|
295
|
+
- Processing state
|
|
296
|
+
|
|
297
|
+
2. **Message Visibility**: All consumer groups see all messages, but each group tracks which messages it has processed independently
|
|
298
|
+
|
|
299
|
+
3. **Partition Locking per Group**: Within a consumer group, partition locking still applies to prevent duplicate processing
|
|
300
|
+
|
|
301
|
+
```javascript
|
|
302
|
+
// Analytics service (Group A)
|
|
303
|
+
const analyticsResult = await client.pop({
|
|
304
|
+
queue: 'events',
|
|
305
|
+
consumerGroup: 'analytics-service'
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// Audit service (Group B) - gets the same messages
|
|
309
|
+
const auditResult = await client.pop({
|
|
310
|
+
queue: 'events',
|
|
311
|
+
consumerGroup: 'audit-service'
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
// Billing service (Group C) - also gets the same messages
|
|
315
|
+
const billingResult = await client.pop({
|
|
316
|
+
queue: 'events',
|
|
317
|
+
consumerGroup: 'billing-service'
|
|
318
|
+
});
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
#### Consumer Group Subscription Modes
|
|
322
|
+
|
|
323
|
+
When a consumer group is created, it can specify when to start consuming messages:
|
|
324
|
+
|
|
325
|
+
```javascript
|
|
326
|
+
// Start from all existing messages
|
|
327
|
+
await client.pop({
|
|
328
|
+
queue: 'events',
|
|
329
|
+
consumerGroup: 'replay-service',
|
|
330
|
+
subscriptionMode: 'all'
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
// Start from messages created after joining
|
|
334
|
+
await client.pop({
|
|
335
|
+
queue: 'events',
|
|
336
|
+
consumerGroup: 'realtime-service',
|
|
337
|
+
subscriptionMode: 'new'
|
|
338
|
+
});
|
|
339
|
+
|
|
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
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### Namespace and Task Filtering
|
|
349
|
+
|
|
350
|
+
Queen supports cross-queue message consumption through namespace and task filtering, with full partition locking support:
|
|
351
|
+
|
|
352
|
+
#### Namespace-Based Routing
|
|
353
|
+
|
|
354
|
+
Group related queues under a namespace and consume from all of them:
|
|
355
|
+
|
|
356
|
+
```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
|
+
});
|
|
364
|
+
|
|
365
|
+
await client.configure({
|
|
366
|
+
queue: 'inventory-updates',
|
|
367
|
+
namespace: 'ecommerce',
|
|
368
|
+
task: 'update',
|
|
369
|
+
options: { leaseTime: 30 }
|
|
370
|
+
});
|
|
371
|
+
|
|
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
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
#### Task-Based Routing
|
|
380
|
+
|
|
381
|
+
Filter messages by specific tasks across namespaces:
|
|
382
|
+
|
|
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
|
+
```
|
|
390
|
+
|
|
391
|
+
#### Partition Locking with Filters
|
|
392
|
+
|
|
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
|
|
397
|
+
|
|
398
|
+
```javascript
|
|
399
|
+
// Consumer 1: Gets messages and locks partitions A, B, C
|
|
400
|
+
const result1 = await client.pop({ namespace: 'ecommerce' });
|
|
401
|
+
|
|
402
|
+
// Consumer 2: Gets messages from different partitions D, E (A, B, C are locked)
|
|
403
|
+
const result2 = await client.pop({ namespace: 'ecommerce' });
|
|
404
|
+
|
|
405
|
+
// No partition overlap between consumers
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Concurrency Control
|
|
409
|
+
|
|
410
|
+
Queen provides several mechanisms for controlling concurrent message processing:
|
|
411
|
+
|
|
412
|
+
#### 1. Partition-Based Concurrency
|
|
413
|
+
|
|
414
|
+
Control parallelism by the number of partitions:
|
|
415
|
+
|
|
416
|
+
```javascript
|
|
417
|
+
// Create multiple partitions for parallel processing
|
|
418
|
+
const partitions = ['worker-1', 'worker-2', 'worker-3', 'worker-4'];
|
|
419
|
+
|
|
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
|
+
});
|
|
428
|
+
|
|
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
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
#### 2. Lease-Based Concurrency
|
|
436
|
+
|
|
437
|
+
Automatic concurrency control through lease timeouts:
|
|
438
|
+
|
|
439
|
+
```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
|
+
});
|
|
448
|
+
|
|
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
|
+
});
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
#### 3. Batch Size Control
|
|
460
|
+
|
|
461
|
+
Limit concurrent processing per consumer:
|
|
462
|
+
|
|
463
|
+
```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
|
+
});
|
|
470
|
+
|
|
471
|
+
// Process batch
|
|
472
|
+
for (const message of batch.messages) {
|
|
473
|
+
await processMessage(message);
|
|
474
|
+
await client.ack(message.transactionId, 'completed');
|
|
475
|
+
}
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
### Message Visibility and Isolation
|
|
479
|
+
|
|
480
|
+
#### Queue Mode (Default)
|
|
481
|
+
|
|
482
|
+
In queue mode, messages are consumed competitively - once a consumer gets a message, no other consumer can see it:
|
|
483
|
+
|
|
484
|
+
```javascript
|
|
485
|
+
// Without consumer group - competitive consumption
|
|
486
|
+
const consumer1 = await client.pop({ queue: 'tasks' });
|
|
487
|
+
const consumer2 = await client.pop({ queue: 'tasks' });
|
|
488
|
+
// Each consumer gets different messages
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
#### Bus Mode (Consumer Groups)
|
|
492
|
+
|
|
493
|
+
In bus mode, all consumer groups see all messages:
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
// With consumer groups - broadcast consumption
|
|
497
|
+
const service1 = await client.pop({
|
|
498
|
+
queue: 'events',
|
|
499
|
+
consumerGroup: 'service-1'
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
const service2 = await client.pop({
|
|
503
|
+
queue: 'events',
|
|
504
|
+
consumerGroup: 'service-2'
|
|
505
|
+
});
|
|
506
|
+
// Both services get the same messages
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
#### Mixed Mode
|
|
510
|
+
|
|
511
|
+
You can combine both patterns in the same system:
|
|
512
|
+
|
|
513
|
+
```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'
|
|
521
|
+
});
|
|
522
|
+
|
|
523
|
+
const analytics = await client.pop({
|
|
524
|
+
queue: 'jobs',
|
|
525
|
+
consumerGroup: 'analytics'
|
|
526
|
+
});
|
|
527
|
+
```
|
|
528
|
+
|
|
529
|
+
### Best Practices
|
|
530
|
+
|
|
531
|
+
#### 1. Partition Strategy
|
|
532
|
+
|
|
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
|
|
537
|
+
|
|
538
|
+
#### 2. Consumer Group Design
|
|
539
|
+
|
|
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
|
|
543
|
+
|
|
544
|
+
#### 3. Lease Management
|
|
545
|
+
|
|
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
|
|
549
|
+
|
|
550
|
+
#### 4. Error Handling
|
|
551
|
+
|
|
552
|
+
```javascript
|
|
553
|
+
try {
|
|
554
|
+
const messages = await client.pop({ queue: 'tasks' });
|
|
555
|
+
|
|
556
|
+
for (const message of messages.messages) {
|
|
557
|
+
try {
|
|
558
|
+
await processMessage(message);
|
|
559
|
+
await client.ack(message.transactionId, 'completed');
|
|
560
|
+
} catch (error) {
|
|
561
|
+
// Log error but don't ack - message will retry
|
|
562
|
+
console.error('Processing failed:', error);
|
|
563
|
+
await client.ack(message.transactionId, 'failed', error.message);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
} catch (error) {
|
|
567
|
+
console.error('Pop failed:', error);
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
## ๐ API Reference
|
|
572
|
+
|
|
573
|
+
### Base URL
|
|
574
|
+
```
|
|
575
|
+
http://localhost:6632/api/v1
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### Push Messages
|
|
579
|
+
|
|
580
|
+
**Endpoint:** `POST /api/v1/push`
|
|
581
|
+
|
|
582
|
+
```javascript
|
|
583
|
+
{
|
|
584
|
+
"items": [
|
|
585
|
+
{
|
|
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
|
|
593
|
+
}
|
|
594
|
+
]
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
**Response:**
|
|
599
|
+
```javascript
|
|
600
|
+
{
|
|
601
|
+
"messages": [
|
|
602
|
+
{
|
|
603
|
+
"id": "018e63b7-6165-453f-88ae-56effa177605",
|
|
604
|
+
"transactionId": "4dfb0478-655b-4c91-bcd9-b7acacf0400f",
|
|
605
|
+
"status": "queued"
|
|
606
|
+
}
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
```
|
|
610
|
+
|
|
611
|
+
### Pop Messages
|
|
612
|
+
|
|
613
|
+
**From Specific Partition:**
|
|
614
|
+
```
|
|
615
|
+
GET /api/v1/pop/queue/{queue}/partition/{partition}?wait=true&timeout=30000&batch=10
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
**From Any Partition in Queue:**
|
|
619
|
+
```
|
|
620
|
+
GET /api/v1/pop/queue/{queue}?wait=true&timeout=30000&batch=10
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
**With Namespace/Task Filter:**
|
|
624
|
+
```
|
|
625
|
+
GET /api/v1/pop?namespace=my-app&task=emails&wait=true&timeout=30000&batch=10
|
|
626
|
+
```
|
|
627
|
+
|
|
628
|
+
**Response:**
|
|
629
|
+
```javascript
|
|
630
|
+
{
|
|
631
|
+
"messages": [
|
|
632
|
+
{
|
|
633
|
+
"id": "018e63b7-6165-453f-88ae-56effa177605",
|
|
634
|
+
"transactionId": "4dfb0478-655b-4c91-bcd9-b7acacf0400f",
|
|
635
|
+
"queue": "email-queue",
|
|
636
|
+
"partition": "urgent",
|
|
637
|
+
"data": { "to": "user@example.com", "subject": "Hello" },
|
|
638
|
+
"retryCount": 0,
|
|
639
|
+
"priority": 10,
|
|
640
|
+
"createdAt": "2023-10-08T12:00:00.000Z",
|
|
641
|
+
"options": { "leaseTime": 300 }
|
|
642
|
+
}
|
|
643
|
+
]
|
|
644
|
+
}
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
### Acknowledge Messages
|
|
648
|
+
|
|
649
|
+
**Single Acknowledgment:**
|
|
650
|
+
```javascript
|
|
651
|
+
POST /api/v1/ack
|
|
652
|
+
{
|
|
653
|
+
"transactionId": "uuid",
|
|
654
|
+
"status": "completed", // "completed" or "failed"
|
|
655
|
+
"error": "optional error" // Required if status is "failed"
|
|
656
|
+
}
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
**Batch Acknowledgment:**
|
|
660
|
+
```javascript
|
|
661
|
+
POST /api/v1/ack/batch
|
|
662
|
+
{
|
|
663
|
+
"acknowledgments": [
|
|
664
|
+
{ "transactionId": "uuid1", "status": "completed" },
|
|
665
|
+
{ "transactionId": "uuid2", "status": "failed", "error": "Processing error" }
|
|
666
|
+
]
|
|
667
|
+
}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Queue Configuration
|
|
671
|
+
|
|
672
|
+
```javascript
|
|
673
|
+
POST /api/v1/configure
|
|
674
|
+
{
|
|
675
|
+
"queue": "email-queue",
|
|
676
|
+
"partition": "urgent", // Optional (defaults to "Default")
|
|
677
|
+
"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
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### Analytics
|
|
688
|
+
|
|
689
|
+
```javascript
|
|
690
|
+
// Get all queues overview
|
|
691
|
+
GET /api/v1/analytics/queues
|
|
692
|
+
|
|
693
|
+
// Get queue statistics
|
|
694
|
+
GET /api/v1/analytics/queue/{queueName}
|
|
695
|
+
|
|
696
|
+
// Get namespace statistics
|
|
697
|
+
GET /api/v1/analytics?namespace={namespace}
|
|
698
|
+
|
|
699
|
+
// Get throughput metrics
|
|
700
|
+
GET /api/v1/analytics/throughput
|
|
701
|
+
|
|
702
|
+
// Get queue depths
|
|
703
|
+
GET /api/v1/analytics/queue-depths
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
## ๐ฑ Client SDK
|
|
707
|
+
|
|
708
|
+
### Installation
|
|
709
|
+
|
|
710
|
+
```javascript
|
|
711
|
+
import { createQueenClient } from './src/client/queenClient.js';
|
|
712
|
+
|
|
713
|
+
const client = createQueenClient({
|
|
714
|
+
baseUrl: 'http://localhost:6632',
|
|
715
|
+
timeout: 30000,
|
|
716
|
+
retryAttempts: 3,
|
|
717
|
+
retryDelay: 1000
|
|
718
|
+
});
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
### Basic Operations
|
|
722
|
+
|
|
723
|
+
```javascript
|
|
724
|
+
// Configure a queue
|
|
725
|
+
await client.configure({
|
|
726
|
+
queue: 'orders',
|
|
727
|
+
options: {
|
|
728
|
+
priority: 10,
|
|
729
|
+
leaseTime: 600,
|
|
730
|
+
retryLimit: 3
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
|
|
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
|
+
});
|
|
742
|
+
|
|
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
|
+
});
|
|
751
|
+
|
|
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
|
+
});
|
|
759
|
+
|
|
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
|
+
}
|
|
769
|
+
```
|
|
770
|
+
|
|
771
|
+
### Consumer Pattern
|
|
772
|
+
|
|
773
|
+
The SDK provides a convenient consumer helper for continuous message processing with two modes:
|
|
774
|
+
|
|
775
|
+
#### Individual Message Processing
|
|
776
|
+
|
|
777
|
+
Process messages one by one (default behavior):
|
|
778
|
+
|
|
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
|
+
});
|
|
795
|
+
|
|
796
|
+
// Stop the consumer when needed
|
|
797
|
+
// stopConsumer();
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
#### Batch Message Processing
|
|
801
|
+
|
|
802
|
+
Process entire batches of messages at once for better performance:
|
|
803
|
+
|
|
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
|
+
});
|
|
831
|
+
```
|
|
832
|
+
|
|
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
|
|
838
|
+
|
|
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)
|
|
843
|
+
|
|
844
|
+
### Advanced Features
|
|
845
|
+
|
|
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
|
+
});
|
|
853
|
+
|
|
854
|
+
// Batch acknowledgment
|
|
855
|
+
await client.ackBatch([
|
|
856
|
+
{ transactionId: 'uuid1', status: 'completed' },
|
|
857
|
+
{ transactionId: 'uuid2', status: 'failed', error: 'Invalid data' }
|
|
858
|
+
]);
|
|
859
|
+
|
|
860
|
+
// Message management
|
|
861
|
+
const messages = await client.messages.list({
|
|
862
|
+
queue: 'orders',
|
|
863
|
+
status: 'failed',
|
|
864
|
+
limit: 100
|
|
865
|
+
});
|
|
866
|
+
|
|
867
|
+
await client.messages.retry('transaction-id');
|
|
868
|
+
await client.messages.moveToDLQ('transaction-id');
|
|
869
|
+
```
|
|
870
|
+
|
|
871
|
+
## ๐ Dashboard
|
|
872
|
+
|
|
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:
|
|
951
|
+
|
|
952
|
+
```javascript
|
|
953
|
+
// Connect to dashboard WebSocket
|
|
954
|
+
const ws = new WebSocket('ws://localhost:6632/ws/dashboard');
|
|
955
|
+
|
|
956
|
+
// Receive real-time updates
|
|
957
|
+
ws.onmessage = (event) => {
|
|
958
|
+
const { event: eventType, data } = JSON.parse(event.data);
|
|
959
|
+
|
|
960
|
+
switch (eventType) {
|
|
961
|
+
case 'queue.depth.updated':
|
|
962
|
+
updateQueueDepth(data);
|
|
963
|
+
break;
|
|
964
|
+
case 'message.processed':
|
|
965
|
+
updateThroughput(data);
|
|
966
|
+
break;
|
|
967
|
+
case 'system.stats':
|
|
968
|
+
updateSystemStats(data);
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
};
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
## ๐ Examples
|
|
975
|
+
|
|
976
|
+
### Basic Email Queue
|
|
977
|
+
|
|
978
|
+
```javascript
|
|
979
|
+
// Configure email queue with priority
|
|
980
|
+
await client.configure({
|
|
981
|
+
queue: 'emails-urgent',
|
|
982
|
+
options: { priority: 10, leaseTime: 300 }
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
await client.configure({
|
|
986
|
+
queue: 'emails-normal',
|
|
987
|
+
options: { priority: 5, leaseTime: 300 }
|
|
988
|
+
});
|
|
989
|
+
|
|
990
|
+
// Send urgent email
|
|
991
|
+
await client.push({
|
|
992
|
+
items: [{
|
|
993
|
+
queue: 'emails',
|
|
994
|
+
partition: 'urgent',
|
|
995
|
+
payload: {
|
|
996
|
+
to: 'admin@company.com',
|
|
997
|
+
subject: 'System Alert',
|
|
998
|
+
body: 'Critical system issue detected'
|
|
999
|
+
}
|
|
1000
|
+
}]
|
|
1001
|
+
});
|
|
1002
|
+
|
|
1003
|
+
// Process emails (urgent emails processed first)
|
|
1004
|
+
const result = await client.pop({
|
|
1005
|
+
queue: 'emails',
|
|
1006
|
+
batch: 10,
|
|
1007
|
+
wait: true
|
|
1008
|
+
});
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
### Delayed Job Processing
|
|
1012
|
+
|
|
1013
|
+
```javascript
|
|
1014
|
+
// Configure queue with delayed processing
|
|
1015
|
+
await client.configure({
|
|
1016
|
+
queue: 'scheduled-jobs',
|
|
1017
|
+
options: {
|
|
1018
|
+
delayedProcessing: 3600, // 1 hour delay
|
|
1019
|
+
priority: 5
|
|
1020
|
+
}
|
|
1021
|
+
});
|
|
1022
|
+
|
|
1023
|
+
// Schedule a job for later processing
|
|
1024
|
+
await client.push({
|
|
1025
|
+
items: [{
|
|
1026
|
+
queue: 'scheduled-jobs',
|
|
1027
|
+
partition: 'daily-reports',
|
|
1028
|
+
payload: {
|
|
1029
|
+
reportType: 'daily-sales',
|
|
1030
|
+
date: '2023-10-08',
|
|
1031
|
+
recipients: ['manager@company.com']
|
|
1032
|
+
}
|
|
1033
|
+
}]
|
|
1034
|
+
});
|
|
1035
|
+
|
|
1036
|
+
// Job will not be available for processing until 1 hour later
|
|
1037
|
+
```
|
|
1038
|
+
|
|
1039
|
+
### Batch Processing with Window Buffer
|
|
1040
|
+
|
|
1041
|
+
```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
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
|
|
1051
|
+
// Send multiple events
|
|
1052
|
+
for (let i = 0; i < 100; i++) {
|
|
1053
|
+
await client.push({
|
|
1054
|
+
items: [{
|
|
1055
|
+
queue: 'analytics',
|
|
1056
|
+
partition: 'events',
|
|
1057
|
+
payload: { userId: i, action: 'page_view', timestamp: Date.now() }
|
|
1058
|
+
}]
|
|
1059
|
+
});
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
// Messages will be held for 60 seconds to allow batching
|
|
1063
|
+
// Then all messages become available at once for efficient processing
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
### Multi-Queue Processing with Priorities
|
|
1067
|
+
|
|
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
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
|
|
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
|
+
});
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
### High-Throughput Batch Processing
|
|
1095
|
+
|
|
1096
|
+
```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
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
|
|
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
|
+
|
|
1115
|
+
try {
|
|
1116
|
+
// Extract all payloads for batch processing
|
|
1117
|
+
const events = messages.map(msg => ({
|
|
1118
|
+
id: msg.transactionId,
|
|
1119
|
+
...msg.data
|
|
1120
|
+
}));
|
|
1121
|
+
|
|
1122
|
+
// Process entire batch efficiently
|
|
1123
|
+
await processAnalyticsBatch(events);
|
|
1124
|
+
|
|
1125
|
+
const processingTime = Date.now() - startTime;
|
|
1126
|
+
console.log(`โ
Batch processed in ${processingTime}ms`);
|
|
1127
|
+
|
|
1128
|
+
} catch (error) {
|
|
1129
|
+
console.error('Batch processing failed:', error);
|
|
1130
|
+
throw error; // Will mark all messages as failed
|
|
1131
|
+
}
|
|
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
|
+
}
|
|
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
|
+
}
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
## โก Performance
|
|
1154
|
+
|
|
1155
|
+
### Benchmarks
|
|
1156
|
+
|
|
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
|
|
1161
|
+
|
|
1162
|
+
### Optimization Features
|
|
1163
|
+
|
|
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
|
|
1169
|
+
|
|
1170
|
+
### Performance Tuning
|
|
1171
|
+
|
|
1172
|
+
```javascript
|
|
1173
|
+
// Environment variables for performance tuning
|
|
1174
|
+
export DB_POOL_SIZE=20 // Database connection pool size
|
|
1175
|
+
export DB_IDLE_TIMEOUT=30000 // Connection idle timeout
|
|
1176
|
+
export DB_CONNECTION_TIMEOUT=2000 // Connection establishment timeout
|
|
1177
|
+
```
|
|
1178
|
+
|
|
1179
|
+
## ๐ Enterprise Features
|
|
1180
|
+
|
|
1181
|
+
Queen includes three powerful enterprise features for production deployments:
|
|
1182
|
+
|
|
1183
|
+
### 1. Encryption
|
|
1184
|
+
Protect sensitive data with AES-256-GCM encryption at the queue level.
|
|
1185
|
+
|
|
1186
|
+
**Setup:**
|
|
1187
|
+
```bash
|
|
1188
|
+
# Set encryption key (64 hex characters = 32 bytes)
|
|
1189
|
+
export QUEEN_ENCRYPTION_KEY=$(openssl rand -hex 32)
|
|
1190
|
+
```
|
|
1191
|
+
|
|
1192
|
+
**Configuration:**
|
|
1193
|
+
```javascript
|
|
1194
|
+
await client.configure({
|
|
1195
|
+
queue: 'sensitive-data',
|
|
1196
|
+
options: {
|
|
1197
|
+
encryptionEnabled: true
|
|
1198
|
+
}
|
|
1199
|
+
});
|
|
1200
|
+
```
|
|
1201
|
+
|
|
1202
|
+
### 2. Message Retention
|
|
1203
|
+
Automatically clean up old messages to prevent storage bloat.
|
|
1204
|
+
|
|
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
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
**Environment:**
|
|
1218
|
+
```bash
|
|
1219
|
+
export RETENTION_INTERVAL=300000 # Cleanup interval in milliseconds
|
|
1220
|
+
```
|
|
1221
|
+
|
|
1222
|
+
### 3. Message Eviction
|
|
1223
|
+
Enforce SLAs by automatically evicting messages that wait too long.
|
|
1224
|
+
|
|
1225
|
+
**Configuration:**
|
|
1226
|
+
```javascript
|
|
1227
|
+
await client.configure({
|
|
1228
|
+
queue: 'time-sensitive',
|
|
1229
|
+
options: {
|
|
1230
|
+
maxWaitTimeSeconds: 60 // Evict messages older than 1 minute
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
```
|
|
1234
|
+
|
|
1235
|
+
**Environment:**
|
|
1236
|
+
```bash
|
|
1237
|
+
export EVICTION_INTERVAL=60000 # Check interval in milliseconds
|
|
1238
|
+
```
|
|
1239
|
+
|
|
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
|
+
}
|
|
1260
|
+
});
|
|
1261
|
+
```
|
|
1262
|
+
|
|
1263
|
+
## โ๏ธ Configuration
|
|
1264
|
+
|
|
1265
|
+
### Environment Variables
|
|
1266
|
+
|
|
1267
|
+
All configuration values have sensible defaults and can be overridden using environment variables. Configuration is centralized in `src/config.js`.
|
|
1268
|
+
|
|
1269
|
+
#### Server Configuration
|
|
1270
|
+
|
|
1271
|
+
```bash
|
|
1272
|
+
# Server basics
|
|
1273
|
+
PORT=6632 # Server port (default: 6632)
|
|
1274
|
+
HOST=0.0.0.0 # Server host (default: 0.0.0.0)
|
|
1275
|
+
WORKER_ID=worker-1 # Worker identifier (default: worker-${process.pid})
|
|
1276
|
+
APP_NAME=queen-uws # Application name for database connections
|
|
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
|
+
```
|
|
1284
|
+
|
|
1285
|
+
#### Database Configuration
|
|
1286
|
+
|
|
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)
|
|
1294
|
+
|
|
1295
|
+
# Connection pool settings
|
|
1296
|
+
DB_POOL_SIZE=20 # Max pool size (default: 20)
|
|
1297
|
+
DB_IDLE_TIMEOUT=30000 # Idle connection timeout in ms (default: 30000)
|
|
1298
|
+
DB_CONNECTION_TIMEOUT=2000 # Connection timeout in ms (default: 2000)
|
|
1299
|
+
DB_STATEMENT_TIMEOUT=30000 # Statement timeout in ms (default: 30000)
|
|
1300
|
+
DB_QUERY_TIMEOUT=30000 # Query timeout in ms (default: 30000)
|
|
1301
|
+
DB_MAX_RETRIES=3 # Max retry attempts for queries (default: 3)
|
|
1302
|
+
```
|
|
1303
|
+
|
|
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)
|
|
1316
|
+
|
|
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)
|
|
1326
|
+
|
|
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)
|
|
1330
|
+
|
|
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)
|
|
1335
|
+
|
|
1336
|
+
# Eviction
|
|
1337
|
+
DEFAULT_MAX_WAIT_TIME_SECONDS=0 # Max wait time before eviction (default: 0 = disabled)
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
#### Background Jobs Configuration
|
|
1341
|
+
|
|
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)
|
|
1350
|
+
|
|
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)
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
#### WebSocket Configuration
|
|
1357
|
+
|
|
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
|
+
```
|
|
1366
|
+
|
|
1367
|
+
#### Encryption Configuration
|
|
1368
|
+
|
|
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
|
+
```
|
|
1375
|
+
|
|
1376
|
+
#### Client SDK Configuration
|
|
1377
|
+
|
|
1378
|
+
```bash
|
|
1379
|
+
# Client defaults
|
|
1380
|
+
QUEEN_BASE_URL=http://localhost:6632 # Default server URL
|
|
1381
|
+
CLIENT_RETRY_ATTEMPTS=3 # Default retry attempts (default: 3)
|
|
1382
|
+
CLIENT_RETRY_DELAY=1000 # Default retry delay in ms (default: 1000)
|
|
1383
|
+
CLIENT_RETRY_BACKOFF=2 # Retry backoff multiplier (default: 2)
|
|
1384
|
+
CLIENT_POOL_SIZE=10 # Client connection pool size (default: 10)
|
|
1385
|
+
CLIENT_REQUEST_TIMEOUT=30000 # Request timeout in ms (default: 30000)
|
|
1386
|
+
```
|
|
1387
|
+
|
|
1388
|
+
#### API Configuration
|
|
1389
|
+
|
|
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
|
+
```
|
|
1396
|
+
|
|
1397
|
+
#### Analytics Configuration
|
|
1398
|
+
|
|
1399
|
+
```bash
|
|
1400
|
+
# Analytics settings
|
|
1401
|
+
ANALYTICS_RECENT_HOURS=24 # Hours to consider for recent stats (default: 24)
|
|
1402
|
+
ANALYTICS_MIN_COMPLETED=5 # Min completed messages for stats (default: 5)
|
|
1403
|
+
RECENT_MESSAGE_WINDOW=60 # Recent message window in seconds (default: 60)
|
|
1404
|
+
RELATED_MESSAGE_WINDOW=3600 # Related message window in seconds (default: 3600)
|
|
1405
|
+
MAX_RELATED_MESSAGES=10 # Max related messages to return (default: 10)
|
|
1406
|
+
```
|
|
1407
|
+
|
|
1408
|
+
#### Monitoring Configuration
|
|
1409
|
+
|
|
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
|
+
```
|
|
1417
|
+
|
|
1418
|
+
#### Logging Configuration
|
|
1419
|
+
|
|
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
|
+
```
|
|
1427
|
+
|
|
1428
|
+
### Queue Options
|
|
1429
|
+
|
|
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
|
+
```
|
|
1453
|
+
|
|
1454
|
+
## ๐งช Testing
|
|
1455
|
+
|
|
1456
|
+
### Run Core Feature Tests
|
|
1457
|
+
|
|
1458
|
+
```bash
|
|
1459
|
+
# Start the server
|
|
1460
|
+
npm start
|
|
1461
|
+
|
|
1462
|
+
# Run comprehensive test suite
|
|
1463
|
+
node src/test/core-features-test.js
|
|
1464
|
+
|
|
1465
|
+
# Run full test suite (more detailed)
|
|
1466
|
+
node src/test/comprehensive-test.js
|
|
1467
|
+
```
|
|
1468
|
+
|
|
1469
|
+
### Test Results
|
|
1470
|
+
|
|
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
|
|
1480
|
+
|
|
1481
|
+
## ๐ค Contributing
|
|
1482
|
+
|
|
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
|
|
1488
|
+
|
|
1489
|
+
## ๐ License
|
|
1490
|
+
|
|
1491
|
+
MIT License - see LICENSE file for details.
|
|
1492
|
+
|
|
1493
|
+
---
|
|
1494
|
+
|
|
1495
|
+
**Queen Message Queue System** - Built for performance, reliability, and scalability. ๐
|