queen-mq 0.2.23 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -136
- package/client-js/client-v2/LOGGING.md +240 -0
- package/client-js/client-v2/Queen.js +389 -0
- package/client-js/client-v2/README.md +1883 -0
- package/client-js/client-v2/buffer/BufferManager.js +215 -0
- package/client-js/client-v2/buffer/MessageBuffer.js +132 -0
- package/client-js/client-v2/builders/QueueBuilder.js +724 -0
- package/client-js/client-v2/builders/TransactionBuilder.js +110 -0
- package/client-js/client-v2/consumer/ConsumerManager.js +390 -0
- package/client-js/client-v2/http/HttpClient.js +215 -0
- package/client-js/client-v2/http/LoadBalancer.js +50 -0
- package/client-js/client-v2/index.js +7 -0
- package/client-js/client-v2/utils/defaults.js +54 -0
- package/client-js/client-v2/utils/logger.js +54 -0
- package/client-js/client-v2/utils/validation.js +31 -0
- package/client-js/test-v2/AI_TEST_SUMMARY.md +226 -0
- package/client-js/test-v2/GETTING_STARTED.md +154 -0
- package/client-js/test-v2/ai_buffering.js +194 -0
- package/client-js/test-v2/ai_error_handling.js +223 -0
- package/client-js/test-v2/ai_lease_renewal.js +206 -0
- package/client-js/test-v2/ai_mixed_scenarios.js +278 -0
- package/client-js/test-v2/ai_priority.js +169 -0
- package/client-js/test-v2/ai_resources.js +217 -0
- package/client-js/test-v2/ai_ttl_retention.js +170 -0
- package/client-js/test-v2/complete.js +59 -0
- package/client-js/test-v2/consume.js +655 -0
- package/client-js/test-v2/dlq.js +82 -0
- package/client-js/test-v2/load.js +177 -0
- package/client-js/test-v2/pop.js +114 -0
- package/client-js/test-v2/push.js +333 -0
- package/client-js/test-v2/queue.js +39 -0
- package/client-js/test-v2/run.js +187 -0
- package/client-js/test-v2/subscription.js +354 -0
- package/client-js/test-v2/transaction.js +443 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
[](LICENSE.md)
|
|
8
8
|
[](https://nodejs.org/)
|
|
9
9
|
|
|
10
|
-
[Quick Start](#js-client-usage) • [Examples](#-examples) • [Webapp](#webapp) • [Server Setup](#install-server-and-configure-it) • [HTTP API](#raw-http-api)
|
|
10
|
+
[Quick Start](#js-client-usage-v2) • [Complete V2 Guide](client-js/client-v2/README.md) • [Examples](#-examples) • [Webapp](#webapp) • [Server Setup](#install-server-and-configure-it) • [HTTP API](#raw-http-api)
|
|
11
11
|
|
|
12
12
|
<p align="center">
|
|
13
13
|
<img src="assets/queen-logo-rose.svg" alt="Queen Logo" width="120" />
|
|
@@ -17,163 +17,173 @@
|
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
QueenMQ is a queue system written in C++ and backed by Postgres. Supports queues and consumer groups.
|
|
23
|
-
|
|
24
|
-
## JS Client usage
|
|
25
|
-
|
|
26
|
-
```js
|
|
27
|
-
import { Queen } from 'queen-mq'
|
|
28
|
-
|
|
29
|
-
const client = new Queen({
|
|
30
|
-
baseUrls: ['http://localhost:6632'],
|
|
31
|
-
timeout: 30000,
|
|
32
|
-
retryAttempts: 3
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
const queue = 'html-processing'
|
|
36
|
-
|
|
37
|
-
// Create a queue
|
|
38
|
-
await client.queue(queue, { leaseTime: 30 });
|
|
20
|
+
Why "Queen"? Because years ago, when I first read the word "queue" in my mind, I read it as "queen".
|
|
39
21
|
|
|
40
|
-
|
|
41
|
-
await client.push(`${queue}/customer-1828`, [ { id: 1 } ]);
|
|
42
|
-
|
|
43
|
-
// Consume data with iterators
|
|
44
|
-
for await (const msg of client.take(queue, { limit: 1 })) {
|
|
45
|
-
console.log(msg.data.id)
|
|
46
|
-
await client.ack(msg) // OR await client.ack(msg, false) for nack
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// Consume data with iterators, getting the entire batch
|
|
50
|
-
for await (const messages of client.takeBatch(queue, { limit: 1, batch: 10, wait: true, timeout: 2000 })) {
|
|
51
|
-
const newMex = messages.map(x => x.data.id * 2)
|
|
52
|
-
await client.ack(messages) // OR await client.ack(messages, false) for nack
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Consume data with a consumer group
|
|
56
|
-
for await (const msg of client.take(`${queue}@analytics-data`, { limit: 2, batch: 2 })) {
|
|
57
|
-
// Do your computation and than ack with consumer group
|
|
58
|
-
await client.ack(msg, true, { group: 'analytics-data' });
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Consume data from any partition of the queue, continusly
|
|
62
|
-
// This "pipeline" is useful for doing exactly one processing
|
|
63
|
-
await client
|
|
64
|
-
.pipeline(queue)
|
|
65
|
-
.withAutoRenewal({
|
|
66
|
-
interval: 5000 // Renew lease every 5 seconds
|
|
67
|
-
})
|
|
68
|
-
.withConcurrency(5) // Five parallel promises
|
|
69
|
-
.take(10, {
|
|
70
|
-
wait: true, // Use long polling
|
|
71
|
-
timeout: 30000 // Long polling length in millisconds
|
|
72
|
-
})
|
|
73
|
-
.processBatch(async (messages) => {
|
|
74
|
-
return messages.map(x => x.data.id * 2);
|
|
75
|
-
})
|
|
76
|
-
.atomically((tx, originalMessages, processedMessages) => { // ack and push are transactional inside atomically
|
|
77
|
-
tx.ack(originalMessages);
|
|
78
|
-
tx.push('another-queue', processedMessages);
|
|
79
|
-
})
|
|
80
|
-
.repeat({ continuous: true })
|
|
81
|
-
.execute();
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
## 📚 Examples
|
|
22
|
+
---
|
|
85
23
|
|
|
86
|
-
|
|
87
|
-
- **[Basic Queue Operations](examples/01-basic-usage.js)** - Create queue, push, take, and ack messages
|
|
88
|
-
- **[Batch Operations](examples/02-batch-operations.js)** - Push and consume messages in batches
|
|
24
|
+
## Introduction
|
|
89
25
|
|
|
90
|
-
|
|
91
|
-
- **[Queue Configuration](examples/06-queue-configuration.js)** - Configure maxSize, windowBuffer, delay, retryLimit, and priority
|
|
92
|
-
- **[Delayed Processing](examples/04-delayed-processing.js)** - Process messages after a delay
|
|
93
|
-
- **[Window Buffer](examples/05-window-buffer.js)** - Delay message availability after push
|
|
26
|
+
QueenMQ is a queue system written in C++ and backed by PostgreSQL, born from the need to manage many FIFO partitions for Smartchat with solid guarantees around delivery and failure handling. During the initial development, I realized that with a few simple additions to the original design, I could build a very powerful and flexible queue system. This project is almost entirely written by AI, with my supervision—only the test files (or a good part of them) are manually written.
|
|
94
27
|
|
|
95
|
-
|
|
96
|
-
-
|
|
97
|
-
-
|
|
28
|
+
Here are the main features:
|
|
29
|
+
- Unlimited FIFO partitions within queues
|
|
30
|
+
- Queue semantics like RabbitMQ
|
|
31
|
+
- Consumer groups over queues like Kafka
|
|
32
|
+
- QoS levels: Exactly-once delivery (with transactionId), at-least-once delivery, and at-most-once delivery
|
|
33
|
+
- Subscription modes for replay (new messages only or from a specific timestamp) and message history control
|
|
34
|
+
- Transactions between operations (push and ack mainly) for atomicity
|
|
35
|
+
- Dead letter queue for failure handling
|
|
36
|
+
- Lease renewal for long-running tasks
|
|
37
|
+
- Message tracing for debugging workflows
|
|
38
|
+
- Encryption of messages at DB level
|
|
98
39
|
|
|
99
|
-
|
|
100
|
-
- **[Transactional Pipelines](examples/03-transactional-pipeline.js)** - Atomic processing with ack and push in a transaction
|
|
40
|
+
The system consists of a PostgreSQL database, a replicated server that can be scaled horizontally (though it won't be the bottleneck), and a client library for interacting with the server. All client-server communication happens over HTTP, and the client library is written in JavaScript (support for other languages is planned). There's also a modern Vue 3 web app for monitoring and managing the system.
|
|
101
41
|
|
|
102
|
-
|
|
103
|
-
- **[Event Streaming](examples/09-event-streaming.js)** - At-most-once delivery with buffering and auto-ack
|
|
42
|
+
With proper batching, the system can handle +100k **messages** per second (not req/s) on modest hardware.
|
|
104
43
|
|
|
105
|
-
|
|
44
|
+
Main documentation:
|
|
45
|
+
- [Client Guide](client-js/client-v2/README.md)
|
|
46
|
+
- [Server Guide](server/README.md)
|
|
47
|
+
- [API Reference](API.md)
|
|
48
|
+
- [Webapp](webapp/README.md)
|
|
106
49
|
|
|
107
|
-
For high-throughput event streams, Queen supports **at-most-once delivery** with server-side buffering and auto-acknowledgment.
|
|
108
50
|
|
|
109
|
-
|
|
51
|
+
## JS Client Usage
|
|
110
52
|
|
|
111
|
-
|
|
53
|
+
> 📖 **[Complete Guide: client-js/client-v2/README.md](client-js/client-v2/README.md)** - Full tutorial with all features!
|
|
112
54
|
|
|
113
55
|
```javascript
|
|
114
|
-
|
|
115
|
-
await client.push('metrics', { cpu: 45, memory: 67 }, {
|
|
116
|
-
bufferMs: 100, // Server batches for 100ms
|
|
117
|
-
bufferMax: 100 // Or until 100 events
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
// Result: 1000 events = ~10 DB writes (instead of 1000)
|
|
121
|
-
```
|
|
56
|
+
import { Queen } from 'queen-mq'
|
|
122
57
|
|
|
123
|
-
|
|
58
|
+
// Connect to Queen
|
|
59
|
+
const queen = new Queen('http://localhost:6632')
|
|
124
60
|
|
|
125
|
-
|
|
61
|
+
// Create a queue
|
|
62
|
+
await queen.queue('tasks').create()
|
|
63
|
+
|
|
64
|
+
// Push messages
|
|
65
|
+
await queen.queue('tasks').push([
|
|
66
|
+
{ data: { job: 'send-email', to: 'alice@example.com' } },
|
|
67
|
+
{ data: { job: 'process-image', id: 123 } }
|
|
68
|
+
])
|
|
69
|
+
|
|
70
|
+
// Consume messages (auto-ack on success, auto-nack on error)
|
|
71
|
+
await queen.queue('tasks').consume(async (message) => {
|
|
72
|
+
console.log('Processing:', message.data)
|
|
73
|
+
// If this succeeds → message completed ✅
|
|
74
|
+
// If this throws → message retried 🔄
|
|
75
|
+
})
|
|
126
76
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
for
|
|
130
|
-
|
|
131
|
-
|
|
77
|
+
// Pop messages manually
|
|
78
|
+
const messages = await queen.queue('tasks').batch(10).pop()
|
|
79
|
+
for (const msg of messages) {
|
|
80
|
+
try {
|
|
81
|
+
await processMessage(msg.data)
|
|
82
|
+
await queen.ack(msg, true) // Success
|
|
83
|
+
} catch (error) {
|
|
84
|
+
await queen.ack(msg, false) // Retry
|
|
85
|
+
}
|
|
132
86
|
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### Fan-Out Pattern (Consumer Groups)
|
|
136
|
-
|
|
137
|
-
Combine buffering + auto-ack + consumer groups for pub/sub:
|
|
138
|
-
|
|
139
|
-
```javascript
|
|
140
|
-
// Publisher (buffered)
|
|
141
|
-
await client.push('events', { action: 'login' }, { bufferMs: 100 });
|
|
142
87
|
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
88
|
+
// Partitions (for ordering)
|
|
89
|
+
await queen
|
|
90
|
+
.queue('user-events')
|
|
91
|
+
.partition('user-123')
|
|
92
|
+
.push([{ data: { event: 'login' } }])
|
|
93
|
+
|
|
94
|
+
// Consumer groups (for scaling)
|
|
95
|
+
await queen
|
|
96
|
+
.queue('emails')
|
|
97
|
+
.group('processors')
|
|
98
|
+
.concurrency(5)
|
|
99
|
+
.consume(async (message) => {
|
|
100
|
+
await sendEmail(message.data)
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
// Subscription modes (control message history)
|
|
104
|
+
// Skip historical messages, only process new ones
|
|
105
|
+
await queen
|
|
106
|
+
.queue('events')
|
|
107
|
+
.group('realtime-monitor')
|
|
108
|
+
.subscriptionMode('new')
|
|
109
|
+
.consume(async (message) => {
|
|
110
|
+
console.log('New event only:', message.data)
|
|
111
|
+
})
|
|
112
|
+
|
|
113
|
+
// Start from a specific timestamp
|
|
114
|
+
const timestamp = '2025-10-28T10:00:00.000Z'
|
|
115
|
+
await queen
|
|
116
|
+
.queue('events')
|
|
117
|
+
.group('replay-from-timestamp')
|
|
118
|
+
.subscriptionFrom(timestamp)
|
|
119
|
+
.consume(async (message) => {
|
|
120
|
+
console.log('Replaying from 10am:', message.data)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
// Transactions (atomic ack + push)
|
|
124
|
+
const [msg] = await queen.queue('input').pop()
|
|
125
|
+
await queen
|
|
126
|
+
.transaction()
|
|
127
|
+
.ack(msg)
|
|
128
|
+
.queue('output')
|
|
129
|
+
.push([{ data: { processed: true } }])
|
|
130
|
+
.commit()
|
|
131
|
+
|
|
132
|
+
// Client-side buffering (for high throughput)
|
|
133
|
+
await queen
|
|
134
|
+
.queue('logs')
|
|
135
|
+
.buffer({ messageCount: 100, timeMillis: 1000 })
|
|
136
|
+
.push([{ data: { level: 'info', message: 'Server started' } }])
|
|
137
|
+
|
|
138
|
+
// Message tracing (for debugging and monitoring)
|
|
139
|
+
await queen.queue('orders').consume(async (msg) => {
|
|
140
|
+
await msg.trace({
|
|
141
|
+
traceName: ['tenant-acme', 'order-flow-123'],
|
|
142
|
+
data: { text: 'Processing started', orderId: msg.data.id }
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
// Process order...
|
|
146
|
+
|
|
147
|
+
await msg.trace({
|
|
148
|
+
traceName: ['tenant-acme', 'order-flow-123'],
|
|
149
|
+
data: { text: 'Order completed' }
|
|
150
|
+
})
|
|
151
|
+
})
|
|
147
152
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
153
|
+
// Graceful shutdown
|
|
154
|
+
await queen.close()
|
|
151
155
|
```
|
|
152
156
|
|
|
153
|
-
|
|
157
|
+
**Key Features:**
|
|
158
|
+
- ✅ Fluent, chainable API
|
|
159
|
+
- ✅ Auto-acknowledgment (or manual control)
|
|
160
|
+
- ✅ Partitions for ordered processing
|
|
161
|
+
- ✅ Consumer groups for scaling
|
|
162
|
+
- ✅ **Subscription modes (new messages only or from timestamp)**
|
|
163
|
+
- ✅ Transactions for atomicity
|
|
164
|
+
- ✅ Client-side buffering for speed
|
|
165
|
+
- ✅ Dead letter queue for failures
|
|
166
|
+
- ✅ Lease renewal for long tasks
|
|
167
|
+
- ✅ **Message tracing for debugging workflows**
|
|
168
|
+
- ✅ Graceful shutdown with buffer flush
|
|
154
169
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
- Normal pushes go directly to PostgreSQL (FIFO preserved)
|
|
158
|
-
- If PostgreSQL is down, messages buffered to file (macOS: `/tmp/queen`, Linux: `/var/lib/queen/buffers`)
|
|
159
|
-
- Automatic replay when PostgreSQL recovers
|
|
160
|
-
- Survives server crashes and restarts
|
|
161
|
-
- Directory auto-created on first run
|
|
170
|
+
## 📚 Examples
|
|
162
171
|
|
|
163
|
-
|
|
172
|
+
### Client
|
|
164
173
|
|
|
165
|
-
**
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
174
|
+
See the **[Complete V2 Guide](client-js/client-v2/README.md)** with 14 parts covering everything from basics to advanced features:
|
|
175
|
+
- Queue creation, push, and consume
|
|
176
|
+
- Partitions and consumer groups
|
|
177
|
+
- **Subscription modes (new messages, timestamps)**
|
|
178
|
+
- Transactions and buffering
|
|
179
|
+
- Dead letter queues
|
|
180
|
+
- Lease renewal
|
|
181
|
+
- Message tracing
|
|
182
|
+
- Complete real-world pipeline example
|
|
183
|
+
- And much more!
|
|
169
184
|
|
|
170
|
-
|
|
185
|
+
**Test Files** (94 working examples): [client-js/test-v2/](client-js/test-v2/)
|
|
171
186
|
|
|
172
|
-
| Feature | Use For | Don't Use For |
|
|
173
|
-
|---------|---------|---------------|
|
|
174
|
-
| **Buffering** | Metrics, logs, analytics, UI updates | Critical tasks, payments |
|
|
175
|
-
| **Auto-Ack** | Fire-and-forget events, notifications | Tasks requiring retry logic |
|
|
176
|
-
| **Failover** | Everything (automatic) | N/A - always beneficial |
|
|
177
187
|
|
|
178
188
|
## Architecture
|
|
179
189
|
|
|
@@ -206,6 +216,23 @@ Queen uses a high-performance **acceptor/worker pattern** with uWebSockets, comb
|
|
|
206
216
|
|
|
207
217
|
This architecture provides high concurrency, efficient connection pooling, and minimal latency for both immediate and long-polling requests.
|
|
208
218
|
|
|
219
|
+
### PostgreSQL Failover
|
|
220
|
+
|
|
221
|
+
Queen automatically buffers messages to disk when PostgreSQL is unavailable - **zero message loss**:
|
|
222
|
+
|
|
223
|
+
- Normal pushes go directly to PostgreSQL (FIFO preserved)
|
|
224
|
+
- If PostgreSQL is down, messages buffered to file (macOS: `/tmp/queen`, Linux: `/var/lib/queen/buffers`)
|
|
225
|
+
- Automatic replay when PostgreSQL recovers
|
|
226
|
+
- Survives server crashes and restarts
|
|
227
|
+
- Directory auto-created on first run
|
|
228
|
+
|
|
229
|
+
**No configuration needed** - failover is automatic!
|
|
230
|
+
|
|
231
|
+
**Custom directory:**
|
|
232
|
+
```bash
|
|
233
|
+
FILE_BUFFER_DIR=/custom/path ./bin/queen-server
|
|
234
|
+
```
|
|
235
|
+
|
|
209
236
|
## Webapp
|
|
210
237
|
|
|
211
238
|
A modern Vue 3 web interface for managing and monitoring Queen MQ.
|
|
@@ -215,7 +242,8 @@ A modern Vue 3 web interface for managing and monitoring Queen MQ.
|
|
|
215
242
|
- 📈 Message throughput visualization
|
|
216
243
|
- 🔍 Queue management and monitoring
|
|
217
244
|
- 👥 Consumer group tracking
|
|
218
|
-
- 💬 Message browser
|
|
245
|
+
- 💬 Message browser with trace timeline
|
|
246
|
+
- 🔎 **Trace explorer for debugging distributed workflows**
|
|
219
247
|
- 📉 Analytics and insights
|
|
220
248
|
- 🌓 Dark/light theme support
|
|
221
249
|
|
|
@@ -285,7 +313,5 @@ You can use Queen directly from HTTP without the JS client.
|
|
|
285
313
|
|
|
286
314
|
### Other TODO Items
|
|
287
315
|
- retention jobs
|
|
288
|
-
- reconsume
|
|
289
|
-
- new client
|
|
290
316
|
- auth
|
|
291
317
|
- streaming engine
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
# Queen Client V2 - Logging Documentation
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The Queen Client V2 includes comprehensive operation logging that captures every significant action performed by the client. Logging is **disabled by default** and can be enabled via the `QUEEN_CLIENT_LOG` environment variable.
|
|
6
|
+
|
|
7
|
+
## Enabling Logging
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
export QUEEN_CLIENT_LOG=true
|
|
11
|
+
node your-app.js
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or inline:
|
|
15
|
+
```bash
|
|
16
|
+
QUEEN_CLIENT_LOG=true node your-app.js
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Log Format
|
|
20
|
+
|
|
21
|
+
All logs follow this format:
|
|
22
|
+
```
|
|
23
|
+
[TIMESTAMP] [LEVEL] [OPERATION] DETAILS
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
- **TIMESTAMP**: ISO 8601 format (e.g., `2025-10-28T10:30:45.123Z`)
|
|
27
|
+
- **LEVEL**: `INFO`, `WARN`, or `ERROR`
|
|
28
|
+
- **OPERATION**: Component and method (e.g., `Queen.push`, `HttpClient.request`)
|
|
29
|
+
- **DETAILS**: JSON object with relevant context
|
|
30
|
+
|
|
31
|
+
### Example Log Output
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
[2025-10-28T10:30:45.123Z] [INFO] [Queen.constructor] {"status":"initialized","urls":1}
|
|
35
|
+
[2025-10-28T10:30:45.234Z] [INFO] [QueueBuilder.push] {"queue":"tasks","partition":"Default","count":5,"buffered":true}
|
|
36
|
+
[2025-10-28T10:30:45.456Z] [INFO] [BufferManager.addMessage] {"queueAddress":"tasks/Default","messageCount":5}
|
|
37
|
+
[2025-10-28T10:30:46.789Z] [INFO] [HttpClient.request] {"method":"POST","url":"http://localhost:6632/api/v1/push","hasBody":true,"timeout":30000}
|
|
38
|
+
[2025-10-28T10:30:46.890Z] [INFO] [HttpClient.response] {"method":"POST","url":"http://localhost:6632/api/v1/push","status":200}
|
|
39
|
+
[2025-10-28T10:30:47.123Z] [INFO] [BufferManager.flushBuffer] {"queueAddress":"tasks/Default","status":"success","messagesSent":5}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Logged Operations
|
|
43
|
+
|
|
44
|
+
### Queen (Main Client)
|
|
45
|
+
|
|
46
|
+
| Operation | Logged Details |
|
|
47
|
+
|-----------|---------------|
|
|
48
|
+
| `Queen.constructor` | Configuration summary, URL count |
|
|
49
|
+
| `Queen.ack` | Batch/single, message count, status, context |
|
|
50
|
+
| `Queen.renew` | Lease ID count, success/failure per lease |
|
|
51
|
+
| `Queen.flushAllBuffers` | Start and completion status |
|
|
52
|
+
| `Queen.getBufferStats` | Buffer statistics |
|
|
53
|
+
| `Queen.close` | Shutdown phases, errors |
|
|
54
|
+
|
|
55
|
+
### QueueBuilder (Queue Operations)
|
|
56
|
+
|
|
57
|
+
| Operation | Logged Details |
|
|
58
|
+
|-----------|---------------|
|
|
59
|
+
| `QueueBuilder.create` | Queue name, namespace, task |
|
|
60
|
+
| `QueueBuilder.delete` | Queue name |
|
|
61
|
+
| `QueueBuilder.push` | Queue, partition, count, buffered flag |
|
|
62
|
+
| `QueueBuilder.pop` | Queue, partition, batch size, wait mode, result count |
|
|
63
|
+
| `QueueBuilder.flushBuffer` | Queue address |
|
|
64
|
+
| `QueueBuilder.dlq` | Queue, consumer group, partition |
|
|
65
|
+
|
|
66
|
+
### HttpClient (Network Operations)
|
|
67
|
+
|
|
68
|
+
| Operation | Logged Details |
|
|
69
|
+
|-----------|---------------|
|
|
70
|
+
| `HttpClient.constructor` | Configuration (timeout, retries, failover) |
|
|
71
|
+
| `HttpClient.request` | Method, URL, body presence, timeout |
|
|
72
|
+
| `HttpClient.response` | Method, URL, HTTP status |
|
|
73
|
+
| `HttpClient.retry` | Attempt number, delay, error message |
|
|
74
|
+
| `HttpClient.failover` | Server count, attempted URLs, failures |
|
|
75
|
+
|
|
76
|
+
### BufferManager (Client-Side Buffering)
|
|
77
|
+
|
|
78
|
+
| Operation | Logged Details |
|
|
79
|
+
|-----------|---------------|
|
|
80
|
+
| `BufferManager.createBuffer` | Queue address, buffer options |
|
|
81
|
+
| `BufferManager.addMessage` | Queue address, current message count |
|
|
82
|
+
| `BufferManager.flushBuffer` | Queue address, message count, status |
|
|
83
|
+
| `BufferManager.flushAllBuffers` | Buffer count, pending flushes |
|
|
84
|
+
| `BufferManager.getStats` | Active buffers, total messages, oldest age |
|
|
85
|
+
| `BufferManager.cleanup` | Buffer count being cleaned |
|
|
86
|
+
|
|
87
|
+
### ConsumerManager (Message Consumption)
|
|
88
|
+
|
|
89
|
+
| Operation | Logged Details |
|
|
90
|
+
|-----------|---------------|
|
|
91
|
+
| `ConsumerManager.start` | Queue, concurrency, batch size, auto-ack |
|
|
92
|
+
| `ConsumerManager.worker` | Worker ID, lifecycle events, processed count |
|
|
93
|
+
| `ConsumerManager.processMessage` | Transaction ID, ack/nack status, errors |
|
|
94
|
+
| `ConsumerManager.processBatch` | Message count, ack/nack status, errors |
|
|
95
|
+
|
|
96
|
+
### TransactionBuilder (Atomic Operations)
|
|
97
|
+
|
|
98
|
+
| Operation | Logged Details |
|
|
99
|
+
|-----------|---------------|
|
|
100
|
+
| `TransactionBuilder.ack` | Message count, status |
|
|
101
|
+
| `TransactionBuilder.queue.push` | Queue name, item count |
|
|
102
|
+
| `TransactionBuilder.commit` | Operation count, required leases, success/failure |
|
|
103
|
+
|
|
104
|
+
### Other Builders
|
|
105
|
+
|
|
106
|
+
| Operation | Logged Details |
|
|
107
|
+
|-----------|---------------|
|
|
108
|
+
| `OperationBuilder.execute` | Method, path, success/failure |
|
|
109
|
+
| `PushBuilder.execute` | Queue, partition, count, buffered flag, results |
|
|
110
|
+
| `DLQBuilder.get` | Queue, consumer group, limit, offset, results |
|
|
111
|
+
|
|
112
|
+
## Use Cases
|
|
113
|
+
|
|
114
|
+
### 1. Debugging
|
|
115
|
+
|
|
116
|
+
Use logging to trace through client operations and identify where issues occur:
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
QUEEN_CLIENT_LOG=true node my-app.js 2>&1 | grep ERROR
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### 2. Performance Analysis
|
|
123
|
+
|
|
124
|
+
Monitor HTTP request/response times and buffer flush patterns:
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
QUEEN_CLIENT_LOG=true node my-app.js 2>&1 | grep HttpClient
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. Audit Trail
|
|
131
|
+
|
|
132
|
+
Create an audit log of all queue operations:
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
QUEEN_CLIENT_LOG=true node my-app.js 2>&1 | tee audit.log
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 4. Development
|
|
139
|
+
|
|
140
|
+
Enable logging during development to understand client behavior:
|
|
141
|
+
|
|
142
|
+
```javascript
|
|
143
|
+
// In .env file
|
|
144
|
+
QUEEN_CLIENT_LOG=true
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### 5. Production Troubleshooting
|
|
148
|
+
|
|
149
|
+
Temporarily enable logging in production to diagnose issues:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
# Enable for one process
|
|
153
|
+
QUEEN_CLIENT_LOG=true pm2 restart my-app --update-env
|
|
154
|
+
|
|
155
|
+
# Disable after troubleshooting
|
|
156
|
+
pm2 restart my-app
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Performance Impact
|
|
160
|
+
|
|
161
|
+
- **Disabled (default)**: Zero performance impact - all logging calls are no-ops
|
|
162
|
+
- **Enabled**: Minimal impact - logging is asynchronous and uses `console.log/warn/error`
|
|
163
|
+
|
|
164
|
+
## Log Levels
|
|
165
|
+
|
|
166
|
+
- **INFO**: Normal operations (most logs)
|
|
167
|
+
- **WARN**: Recoverable issues (retries, failover, network errors)
|
|
168
|
+
- **ERROR**: Operation failures (push failed, ack failed, etc.)
|
|
169
|
+
|
|
170
|
+
## Filtering Logs
|
|
171
|
+
|
|
172
|
+
### By Component
|
|
173
|
+
```bash
|
|
174
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "HttpClient"
|
|
175
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "BufferManager"
|
|
176
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "ConsumerManager"
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### By Level
|
|
180
|
+
```bash
|
|
181
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "ERROR"
|
|
182
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "WARN"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### By Operation
|
|
186
|
+
```bash
|
|
187
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "push"
|
|
188
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "ack"
|
|
189
|
+
QUEEN_CLIENT_LOG=true node app.js 2>&1 | grep "pop"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Integration with Log Aggregation
|
|
193
|
+
|
|
194
|
+
The structured JSON format makes it easy to integrate with log aggregation tools:
|
|
195
|
+
|
|
196
|
+
### Winston
|
|
197
|
+
```javascript
|
|
198
|
+
import winston from 'winston'
|
|
199
|
+
|
|
200
|
+
// Redirect console.log to Winston
|
|
201
|
+
console.log = winston.info
|
|
202
|
+
console.error = winston.error
|
|
203
|
+
console.warn = winston.warn
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Pino
|
|
207
|
+
```javascript
|
|
208
|
+
import pino from 'pino'
|
|
209
|
+
const logger = pino()
|
|
210
|
+
|
|
211
|
+
console.log = (msg) => logger.info(msg)
|
|
212
|
+
console.error = (msg) => logger.error(msg)
|
|
213
|
+
console.warn = (msg) => logger.warn(msg)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### Datadog, CloudWatch, etc.
|
|
217
|
+
|
|
218
|
+
The ISO 8601 timestamps and JSON format are compatible with most log aggregation services.
|
|
219
|
+
|
|
220
|
+
## Best Practices
|
|
221
|
+
|
|
222
|
+
1. **Disable in Production**: Only enable when needed for troubleshooting
|
|
223
|
+
2. **Use Log Rotation**: If keeping logs enabled, use log rotation to manage disk space
|
|
224
|
+
3. **Filter Sensitive Data**: Payloads are NOT logged - only metadata
|
|
225
|
+
4. **Monitor Log Volume**: High-throughput applications generate many logs when enabled
|
|
226
|
+
5. **Use Structured Search**: Leverage JSON format for precise filtering
|
|
227
|
+
|
|
228
|
+
## Implementation Details
|
|
229
|
+
|
|
230
|
+
The logging system is implemented in `utils/logger.js` and imported by all major components:
|
|
231
|
+
|
|
232
|
+
- `Queen.js` - Main client operations
|
|
233
|
+
- `HttpClient.js` - Network layer
|
|
234
|
+
- `BufferManager.js` - Client-side buffering
|
|
235
|
+
- `ConsumerManager.js` - Message consumption
|
|
236
|
+
- `QueueBuilder.js` - Queue operations
|
|
237
|
+
- `TransactionBuilder.js` - Atomic transactions
|
|
238
|
+
|
|
239
|
+
All logging calls check the `QUEEN_CLIENT_LOG` environment variable and are no-ops when disabled, ensuring zero performance impact by default.
|
|
240
|
+
|