queen-mq 0.1.1 → 0.1.3

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 (149) hide show
  1. package/API.md +1226 -0
  2. package/AUTH.md +2044 -0
  3. package/LICENSE.md +202 -0
  4. package/PROGRAMMATIC_SERVER.md +190 -0
  5. package/README.md +303 -53
  6. package/WEBAPP.md +1889 -0
  7. package/assets/dashboard-01.png +0 -0
  8. package/assets/queen-logo-blue.svg +210 -0
  9. package/assets/queen-logo-cyan.svg +210 -0
  10. package/assets/queen-logo-indigo.svg +210 -0
  11. package/assets/queen-logo-orange.svg +210 -0
  12. package/assets/queen-logo-pink.svg +210 -0
  13. package/assets/queen-logo-purple.svg +210 -0
  14. package/assets/queen-logo-rose.svg +239 -0
  15. package/assets/queen-logo.svg +263 -0
  16. package/examples/batch-processing.js +58 -0
  17. package/examples/programmatic-server.js +58 -0
  18. package/examples/test-cache-multi-server.js +2 -2
  19. package/examples/test-connection-recovery.js +66 -0
  20. package/examples/test-dashboard-api.js +200 -0
  21. package/package.json +4 -2
  22. package/server.log +1 -0
  23. package/src/benchmark/consumer.js +207 -0
  24. package/src/benchmark/consumer_multi.js +216 -0
  25. package/src/benchmark/producer.js +75 -0
  26. package/src/benchmark/producer_multi.js +115 -0
  27. package/src/client/client.js +219 -17
  28. package/src/client/index.js +4 -3
  29. package/src/cluster-server.js +242 -0
  30. package/src/config.js +19 -5
  31. package/src/database/connection.js +42 -16
  32. package/src/database/poolManager.js +7 -0
  33. package/src/database/schema-v2.sql +194 -130
  34. package/src/managers/queueManagerOptimized.js +852 -933
  35. package/src/managers/systemEventManager.js +8 -3
  36. package/src/routes/messages.js +127 -57
  37. package/src/routes/pop.js +27 -43
  38. package/src/routes/resources.js +61 -27
  39. package/src/routes/status.js +1037 -0
  40. package/src/server.js +704 -642
  41. package/src/services/evictionService.js +57 -28
  42. package/src/services/retentionService.js +44 -11
  43. package/src/services/startupSync.js +1 -1
  44. package/src/test/advanced-pattern-tests.js +6 -6
  45. package/src/test/bus-mode-tests.js +24 -11
  46. package/src/test/core-tests.js +110 -0
  47. package/src/test/edge-case-tests.js +12 -5
  48. package/src/test/enterprise-tests.js +48 -15
  49. package/src/test/test-new.js +3 -1
  50. package/src/test/test.js +1 -1
  51. package/src/test/utils.js +1 -1
  52. package/src/test/window-buffer-test.js +114 -0
  53. package/src/utils/streaming.js +231 -0
  54. package/src/utils/uuid.js +2 -2
  55. package/src/websocket/wsServer.js +10 -3
  56. package/test-keepalive-v2.sh +22 -0
  57. package/webapp/COLOR_GUIDE.md +118 -0
  58. package/webapp/README.md +143 -0
  59. package/webapp/index.html +14 -0
  60. package/webapp/package-lock.json +3184 -0
  61. package/webapp/package.json +25 -0
  62. package/webapp/postcss.config.js +7 -0
  63. package/webapp/public/assets/queen-logo-blue.svg +210 -0
  64. package/webapp/public/assets/queen-logo-cyan.svg +210 -0
  65. package/webapp/public/assets/queen-logo-indigo.svg +210 -0
  66. package/webapp/public/assets/queen-logo-orange.svg +210 -0
  67. package/webapp/public/assets/queen-logo-pink.svg +210 -0
  68. package/webapp/public/assets/queen-logo-purple.svg +210 -0
  69. package/webapp/public/assets/queen-logo-rose.svg +239 -0
  70. package/webapp/public/assets/queen-logo.svg +263 -0
  71. package/webapp/src/App.vue +19 -0
  72. package/webapp/src/api/analytics.js +10 -0
  73. package/webapp/src/api/client.js +29 -0
  74. package/webapp/src/api/consumers.js +52 -0
  75. package/webapp/src/api/health.js +7 -0
  76. package/webapp/src/api/messages.js +26 -0
  77. package/webapp/src/api/queues.js +14 -0
  78. package/webapp/src/api/resources.js +8 -0
  79. package/webapp/src/assets/styles/main.css +357 -0
  80. package/webapp/src/components/analytics/AnalyticsFilters.vue +87 -0
  81. package/webapp/src/components/analytics/AnalyticsMetrics.vue +57 -0
  82. package/webapp/src/components/analytics/MessageDistributionChart.vue +111 -0
  83. package/webapp/src/components/analytics/MessageFlowChart.vue +173 -0
  84. package/webapp/src/components/analytics/TimeRangeSelector.vue +27 -0
  85. package/webapp/src/components/analytics/TopQueuesChart.vue +132 -0
  86. package/webapp/src/components/common/ConfirmDialog.vue +56 -0
  87. package/webapp/src/components/common/LoadingSpinner.vue +6 -0
  88. package/webapp/src/components/common/MetricCard.vue +43 -0
  89. package/webapp/src/components/common/StatusBadge.vue +45 -0
  90. package/webapp/src/components/dashboard/MessageStatusCard.vue +50 -0
  91. package/webapp/src/components/dashboard/PerformanceCard.vue +38 -0
  92. package/webapp/src/components/dashboard/ThroughputChart.vue +182 -0
  93. package/webapp/src/components/dashboard/TopQueuesTable.vue +53 -0
  94. package/webapp/src/components/layout/AppLayout.vue +110 -0
  95. package/webapp/src/components/layout/AppSidebar.vue +304 -0
  96. package/webapp/src/components/messages/MessageDetailPanel.vue +242 -0
  97. package/webapp/src/components/messages/MessageFilters.vue +101 -0
  98. package/webapp/src/components/queue-detail/PartitionList.vue +79 -0
  99. package/webapp/src/components/queue-detail/PushMessageModal.vue +175 -0
  100. package/webapp/src/components/queue-detail/QueueConfig.vue +63 -0
  101. package/webapp/src/components/queue-detail/QueueDetailHeader.vue +53 -0
  102. package/webapp/src/components/queue-detail/RecentMessages.vue +76 -0
  103. package/webapp/src/components/queues/CreateQueueModal.vue +193 -0
  104. package/webapp/src/components/queues/QueueFilters.vue +90 -0
  105. package/webapp/src/composables/useApi.js +34 -0
  106. package/webapp/src/composables/useTheme.js +36 -0
  107. package/webapp/src/main.js +11 -0
  108. package/webapp/src/router/index.js +42 -0
  109. package/webapp/src/utils/colors.js +96 -0
  110. package/webapp/src/utils/formatters.js +49 -0
  111. package/webapp/src/views/Analytics.vue +377 -0
  112. package/webapp/src/views/ConsumerGroups.vue +433 -0
  113. package/webapp/src/views/Dashboard.vue +418 -0
  114. package/webapp/src/views/Messages.vue +363 -0
  115. package/webapp/src/views/QueueDetail.vue +582 -0
  116. package/webapp/src/views/Queues.vue +496 -0
  117. package/webapp/tailwind.config.js +25 -0
  118. package/webapp/vite.config.js +10 -0
  119. package/dashboard/.vscode/extensions.json +0 -3
  120. package/dashboard/README.md +0 -5
  121. package/dashboard/index.html +0 -14
  122. package/dashboard/package-lock.json +0 -1458
  123. package/dashboard/package.json +0 -25
  124. package/dashboard/public/vite.svg +0 -1
  125. package/dashboard/src/App.vue +0 -29
  126. package/dashboard/src/assets/styles/main.css +0 -908
  127. package/dashboard/src/assets/vue.svg +0 -1
  128. package/dashboard/src/components/cards/MetricCard.vue +0 -298
  129. package/dashboard/src/components/charts/QueueDepthChart.vue +0 -276
  130. package/dashboard/src/components/charts/QueueLagChart.vue +0 -436
  131. package/dashboard/src/components/charts/ThroughputChart.vue +0 -302
  132. package/dashboard/src/components/common/ActivityFeed.vue +0 -251
  133. package/dashboard/src/components/layout/AppHeader.vue +0 -208
  134. package/dashboard/src/components/layout/AppLayout.vue +0 -88
  135. package/dashboard/src/components/layout/AppSidebar.vue +0 -261
  136. package/dashboard/src/main.js +0 -44
  137. package/dashboard/src/router.js +0 -54
  138. package/dashboard/src/services/api.js +0 -187
  139. package/dashboard/src/services/websocket.js +0 -167
  140. package/dashboard/src/utils/constants.js +0 -56
  141. package/dashboard/src/utils/helpers.js +0 -118
  142. package/dashboard/src/views/Analytics.vue +0 -912
  143. package/dashboard/src/views/Dashboard.vue +0 -906
  144. package/dashboard/src/views/Messages.vue +0 -437
  145. package/dashboard/src/views/QueueDetail.vue +0 -501
  146. package/dashboard/src/views/Queues.vue +0 -333
  147. package/dashboard/vite.config.js +0 -30
  148. package/src/client/queenClient.js +0 -513
  149. package/src/routes/analytics.js +0 -812
package/README.md CHANGED
@@ -9,9 +9,11 @@
9
9
 
10
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
11
 
12
- </div>
12
+ <p align="center">
13
+ <img src="assets/queen-logo.svg" alt="Queen Logo" width="120" />
14
+ </p>
13
15
 
14
- ![Queen Dashboard](assets/dashboard.png)
16
+ </div>
15
17
 
16
18
  ---
17
19
 
@@ -22,12 +24,14 @@
22
24
  ### Why Queen?
23
25
 
24
26
  **🚀 Developer-First API**
25
- - **4 methods, infinite patterns**: `queue()`, `push()`, `take()`, `ack()`
27
+ - **4 core methods, infinite patterns**: `queue()`, `push()`, `take()`, `ack()`
26
28
  - **Async iteration**: Process messages with familiar `for await` syntax
29
+ - **Batch processing**: Use `takeBatch()` for 250k+ msg/sec throughput on millions of messages
27
30
  - **Smart addressing**: `orders/urgent@workers` - queue, partition, and consumer group in one
28
31
 
29
32
  **⚡ Production-Ready Performance**
30
- - **10,000+ msg/sec** throughput with sub-10ms latency
33
+ - **100,000+ msg/sec** throughput with cursor-based consumption
34
+ - **Constant-time batch operations** - O(batch_size) regardless of queue depth
31
35
  - **Long polling** for event-driven, real-time message delivery
32
36
  - **Partition locking** prevents duplicate processing across consumers
33
37
  - **Connection pooling** and optimized batch operations
@@ -49,6 +53,7 @@
49
53
  - **Rich Analytics**: Throughput, lag, queue depth metrics
50
54
  - **Message Browser**: Search, inspect, and retry messages
51
55
  - **System Health**: Database, memory, and performance metrics
56
+ - **Cursor Tracking**: Monitor consumption progress per consumer group
52
57
 
53
58
  ### Use Cases
54
59
 
@@ -67,6 +72,7 @@
67
72
  - [Client Examples](#-client-examples)
68
73
  - [Server Setup](#-server-setup)
69
74
  - [Core Concepts](#-core-concepts)
75
+ - [Cursor-Based Consumption Strategy](#-cursor-based-consumption-strategy)
70
76
  - [HTTP API Reference](#-http-api-reference)
71
77
  - [Dashboard](#-dashboard)
72
78
  - [Configuration](#-configuration)
@@ -128,6 +134,33 @@ npm install
128
134
  node init-db.js
129
135
  ```
130
136
 
137
+ ### Running the Server
138
+
139
+ **Option 1: Standalone Server (Traditional)**
140
+
141
+ ```bash
142
+ npm start
143
+ ```
144
+
145
+ **Option 2: Programmatic Server (New in v0.1.2)**
146
+
147
+ ```javascript
148
+ import { QueenServer } from 'queen-mq';
149
+
150
+ // Start server with default config
151
+ const server = await QueenServer();
152
+
153
+ // Or with custom options
154
+ const server = await QueenServer({
155
+ port: 3000,
156
+ host: '127.0.0.1'
157
+ });
158
+
159
+ console.log(`Server running at http://${server.host}:${server.port}`);
160
+ ```
161
+
162
+ This allows you to embed Queen MQ directly in your application, run multiple instances, or easily start/stop servers in tests. See [PROGRAMMATIC_SERVER.md](./PROGRAMMATIC_SERVER.md) for more details.
163
+
131
164
  ### Set Environment (Optional)
132
165
 
133
166
  ```bash
@@ -252,6 +285,26 @@ for await (const message of client.take('orders/urgent')) {
252
285
  await processUrgentOrder(message.data);
253
286
  await client.ack(message);
254
287
  }
288
+
289
+ // Use takeBatch to get arrays of messages (higher throughput)
290
+ for await (const messages of client.takeBatch('orders', {
291
+ batch: 1000, // Fetch 1000 at a time
292
+ wait: true
293
+ })) {
294
+ // messages is an array of up to 1000 messages
295
+ console.log(`Processing batch of ${messages.length} messages`);
296
+
297
+ try {
298
+ // Process entire batch
299
+ await processBatch(messages.map(m => m.data));
300
+
301
+ // Acknowledge entire batch at once (efficient!)
302
+ await client.ack(messages); // Pass array for batch ack
303
+ } catch (error) {
304
+ // Mark entire batch as failed
305
+ await client.ack(messages, false, { error: error.message });
306
+ }
307
+ }
255
308
  ```
256
309
 
257
310
  #### 4. Acknowledge Messages
@@ -313,7 +366,7 @@ for await (const message of client.take('tasks', {
313
366
  #### Batch Processing
314
367
 
315
368
  ```javascript
316
- // Accumulate and process in batches
369
+ // Method 1: Manual batching with take()
317
370
  const batch = [];
318
371
  for await (const message of client.take('analytics', { batch: 100 })) {
319
372
  batch.push(message);
@@ -328,6 +381,15 @@ for await (const message of client.take('analytics', { batch: 100 })) {
328
381
  batch.length = 0;
329
382
  }
330
383
  }
384
+
385
+ // Method 2: Direct batch processing with takeBatch() (RECOMMENDED)
386
+ for await (const messages of client.takeBatch('analytics', { batch: 1000 })) {
387
+ // messages is already an array!
388
+ await processBatch(messages.map(m => m.data));
389
+
390
+ // Single batch acknowledgment (much faster!)
391
+ await client.ack(messages);
392
+ }
331
393
  ```
332
394
 
333
395
  #### Parallel Processing with Partitions
@@ -881,6 +943,190 @@ await client.queue('time-sensitive', {
881
943
 
882
944
  ---
883
945
 
946
+ ## 🚀 Cursor-Based Consumption Strategy
947
+
948
+ Queen uses a **cursor-based consumption model** for optimal performance at scale, providing O(batch_size) constant-time operations regardless of queue depth.
949
+
950
+ ### How It Works
951
+
952
+ 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.
953
+
954
+ **Partition Cursors:**
955
+
956
+ Each partition maintains a cursor position per consumer group:
957
+ - `last_consumed_created_at`: Timestamp of last consumed message
958
+ - `last_consumed_id`: UUID of last consumed message (tie-breaker for same timestamp)
959
+ - `total_messages_consumed`: Running count of consumed messages
960
+
961
+ The cursor always moves **forward** in time, ensuring strict FIFO ordering.
962
+
963
+ ### The takeBatch Method
964
+
965
+ Queen provides two consumption methods:
966
+
967
+ **1. `take()` - Individual message iterator:**
968
+ ```javascript
969
+ // Processes messages one at a time
970
+ for await (const message of client.take('orders', { batch: 1000 })) {
971
+ await processOrder(message.data);
972
+ await client.ack(message);
973
+ }
974
+ ```
975
+
976
+ **2. `takeBatch()` - Array iterator (HIGH PERFORMANCE):**
977
+ ```javascript
978
+ // Yields arrays of messages - achieves 100k+ msg/s throughput
979
+ for await (const messages of client.takeBatch('orders', { batch: 1000 })) {
980
+ // messages is an array of up to 1000 message objects
981
+ await processBatch(messages.map(m => m.data));
982
+
983
+ // Batch acknowledge - single DB transaction for all messages
984
+ await client.ack(messages);
985
+ }
986
+ ```
987
+
988
+ **Under the hood**, both methods use cursor-based batch retrieval:
989
+
990
+ ```sql
991
+ -- Cursor-based query (simplified)
992
+ SELECT * FROM messages
993
+ WHERE partition_id = $1
994
+ AND id > $2::uuid -- Start after last cursor position
995
+ ORDER BY created_at ASC, id ASC
996
+ LIMIT $3 -- Batch size
997
+ FOR UPDATE SKIP LOCKED
998
+ ```
999
+
1000
+ **Key characteristics:**
1001
+ 1. **Constant-time**: Performance stays consistent whether you've consumed 0% or 99% of messages
1002
+ 2. **FIFO guarantee**: Messages always returned in creation order
1003
+ 3. **Lock-free scanning**: `SKIP LOCKED` prevents contention between consumers
1004
+ 4. **Efficient**: No table scans - direct cursor-based access using UUIDv7 (time-ordered)
1005
+
1006
+ **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.
1007
+
1008
+ ### Batch Acknowledgment Semantics
1009
+
1010
+ Queen handles batch acknowledgments intelligently:
1011
+
1012
+ **Partial Success** (some messages succeed, some fail):
1013
+ ```javascript
1014
+ // Batch: 10,000 messages
1015
+ // Success: 9,999 messages
1016
+ // Failed: 1 message
1017
+
1018
+ // Behavior:
1019
+ // ✅ Cursor advances past all 10,000 messages
1020
+ // ✅ Failed message moved to Dead Letter Queue
1021
+ // ✅ Next take() starts from message 10,001
1022
+ // ✅ FIFO maintained, no redelivery of successful messages
1023
+ ```
1024
+
1025
+ **Total Batch Failure** (all messages fail):
1026
+ ```javascript
1027
+ // Batch: 10,000 messages
1028
+ // Success: 0 messages
1029
+ // Failed: 10,000 messages
1030
+
1031
+ // Behavior:
1032
+ // ❌ Cursor DOES NOT advance
1033
+ // ❌ Messages NOT moved to DLQ
1034
+ // ✅ Lease released
1035
+ // ✅ Next take() gets SAME batch (retry)
1036
+ // ✅ Allows recovery from transient failures
1037
+ ```
1038
+
1039
+ This design handles transient failures (network issues, service outages) gracefully while preventing poison messages from blocking the queue.
1040
+
1041
+ ### Performance Comparison
1042
+
1043
+ | Operation | Traditional Approach | Cursor Approach | Improvement |
1044
+ |-----------|---------------------|-----------------|-------------|
1045
+ | Pop @ 0% consumed | O(partition_size) | O(batch_size) | Same |
1046
+ | Pop @ 50% consumed | O(partition_size) | O(batch_size) | **10-100x faster** |
1047
+ | Pop @ 99% consumed | O(partition_size) | O(batch_size) | **100-1000x faster** |
1048
+
1049
+ **Real-world benchmark** (1M messages):
1050
+ ```
1051
+ Traditional:
1052
+ Early batches: 300ms per pop
1053
+ Late batches: 3500ms per pop (10x degradation)
1054
+
1055
+ Cursor-based:
1056
+ Early batches: 150ms per pop
1057
+ Late batches: 200ms per pop (constant!)
1058
+ ```
1059
+
1060
+ ### Dead Letter Queue
1061
+
1062
+ Individual message failures are moved to the Dead Letter Queue for inspection and manual intervention:
1063
+
1064
+ ```javascript
1065
+ // Monitor DLQ
1066
+ const response = await fetch('http://localhost:6632/api/v1/analytics/dlq');
1067
+ const dlqMessages = await response.json();
1068
+
1069
+ // Inspect failed messages
1070
+ for (const msg of dlqMessages) {
1071
+ console.log(`Failed: ${msg.error_message}`);
1072
+
1073
+ // After fixing issue, can re-push if needed
1074
+ await client.push(msg.queue, fixedPayload);
1075
+ }
1076
+ ```
1077
+
1078
+ **DLQ Query:**
1079
+ ```sql
1080
+ SELECT * FROM queen.dead_letter_queue
1081
+ WHERE consumer_group = 'my-group'
1082
+ ORDER BY failed_at DESC
1083
+ LIMIT 100;
1084
+ ```
1085
+
1086
+ ### Batch Size Guidelines
1087
+
1088
+ Choose batch sizes based on your workload:
1089
+
1090
+ **Smaller batches (100-1,000):**
1091
+ - ✅ Faster individual batch processing
1092
+ - ✅ Less impact if entire batch fails
1093
+ - ✅ Lower memory footprint
1094
+ - ❌ More network round-trips
1095
+
1096
+ **Larger batches (5,000-10,000):**
1097
+ - ✅ Higher throughput (100,000+ msg/sec achievable)
1098
+ - ✅ Fewer network round-trips
1099
+ - ✅ Better database efficiency
1100
+ - ❌ More messages retry if entire batch fails
1101
+ - ❌ Higher memory usage
1102
+
1103
+ **Recommendation:** Start with 1,000-2,000 for balanced performance. Increase to 5,000-10,000 for maximum throughput with reliable processing.
1104
+
1105
+ ### Monitoring Cursor Progress
1106
+
1107
+ Track consumption progress via SQL:
1108
+
1109
+ ```sql
1110
+ -- View cursor positions
1111
+ SELECT
1112
+ p.name as partition,
1113
+ pc.consumer_group,
1114
+ pc.total_messages_consumed,
1115
+ pc.total_batches_consumed,
1116
+ pc.last_consumed_at,
1117
+ EXTRACT(EPOCH FROM (NOW() - pc.last_consumed_at)) as seconds_since_last_consume
1118
+ FROM queen.partition_cursors pc
1119
+ JOIN queen.partitions p ON p.id = pc.partition_id
1120
+ ORDER BY pc.last_consumed_at DESC;
1121
+
1122
+ -- Monitor DLQ
1123
+ SELECT COUNT(*) as failed_count, consumer_group
1124
+ FROM queen.dead_letter_queue
1125
+ GROUP BY consumer_group;
1126
+ ```
1127
+
1128
+ ---
1129
+
884
1130
  ## 🔌 HTTP API Reference
885
1131
 
886
1132
  Base URL: `http://localhost:6632/api/v1`
@@ -1067,6 +1313,12 @@ POST /api/v1/messages/{transactionId}/dlq
1067
1313
  DELETE /api/v1/queues/{queue}/clear
1068
1314
  ```
1069
1315
 
1316
+ **Delete queue:**
1317
+ ```
1318
+ DELETE /api/v1/resources/queues/{queue}
1319
+ ```
1320
+ _Note: Deletes the queue and all its partitions, messages, and related data._
1321
+
1070
1322
  ### System Health
1071
1323
 
1072
1324
  **Health check:**
@@ -1108,10 +1360,12 @@ See [API.md](API.md) for complete API documentation.
1108
1360
 
1109
1361
  Queen includes a comprehensive web dashboard for monitoring and management.
1110
1362
 
1363
+ [Dashboard](/assets/dashboard-01.png)
1364
+
1111
1365
  ### Access
1112
1366
 
1113
1367
  1. Start the server: `npm start`
1114
- 2. Open browser: `http://localhost:6632`
1368
+ 2. Open browser: `http://localhost:4000`
1115
1369
  3. WebSocket connection provides real-time updates
1116
1370
 
1117
1371
  ### Features
@@ -1496,7 +1750,7 @@ Promise.all([
1496
1750
  await emitEvents();
1497
1751
  ```
1498
1752
 
1499
- ### Example 4: Batch Processing
1753
+ ### Example 4: Batch Processing (High Throughput)
1500
1754
 
1501
1755
  ```javascript
1502
1756
  import { Queen } from 'queen-mq';
@@ -1515,7 +1769,7 @@ await client.queue('data-processing', {
1515
1769
  // Producer: Send data
1516
1770
  async function sendData() {
1517
1771
  const records = [];
1518
- for (let i = 0; i < 1000; i++) {
1772
+ for (let i = 0; i < 100000; i++) {
1519
1773
  records.push({ id: i, value: Math.random() });
1520
1774
  }
1521
1775
 
@@ -1523,45 +1777,34 @@ async function sendData() {
1523
1777
  await client.push('data-processing/analytics', records);
1524
1778
  }
1525
1779
 
1526
- // Consumer: Batch processor
1780
+ // Consumer: HIGH PERFORMANCE batch processor using takeBatch()
1527
1781
  async function batchProcessor() {
1528
- const BATCH_SIZE = 100;
1529
- const batch = [];
1782
+ const BATCH_SIZE = 5000; // Large batches for 100k+ msg/s throughput
1530
1783
 
1531
- for await (const message of client.take('data-processing/analytics', {
1784
+ // takeBatch() yields arrays directly - no manual batching needed!
1785
+ for await (const messages of client.takeBatch('data-processing/analytics', {
1532
1786
  batch: BATCH_SIZE,
1533
1787
  wait: true,
1534
1788
  timeout: 30000
1535
1789
  })) {
1536
- batch.push(message);
1537
-
1538
- // Process when batch is full
1539
- if (batch.length >= BATCH_SIZE) {
1540
- try {
1541
- console.log(`Processing batch of ${batch.length} records`);
1542
-
1543
- // Extract data
1544
- const records = batch.map(m => m.data);
1545
-
1546
- // Bulk process
1547
- await bulkInsertToDatabase(records);
1548
-
1549
- // Acknowledge all
1550
- for (const msg of batch) {
1551
- await client.ack(msg);
1552
- }
1553
-
1554
- console.log(`✓ Batch complete`);
1555
- batch.length = 0;
1556
- } catch (error) {
1557
- console.error('Batch processing failed:', error);
1558
-
1559
- // Mark all as failed
1560
- for (const msg of batch) {
1561
- await client.ack(msg, false);
1562
- }
1563
- batch.length = 0;
1564
- }
1790
+ try {
1791
+ console.log(`Processing batch of ${messages.length} records`);
1792
+
1793
+ // Extract data
1794
+ const records = messages.map(m => m.data);
1795
+
1796
+ // Bulk process (single DB operation)
1797
+ await bulkInsertToDatabase(records);
1798
+
1799
+ // Batch acknowledge (single DB transaction!)
1800
+ await client.ack(messages);
1801
+
1802
+ console.log(`✓ Batch complete in single transaction`);
1803
+ } catch (error) {
1804
+ console.error('Batch processing failed:', error);
1805
+
1806
+ // Mark entire batch as failed (single transaction)
1807
+ await client.ack(messages, false, { error: error.message });
1565
1808
  }
1566
1809
  }
1567
1810
  }
@@ -1569,6 +1812,12 @@ async function batchProcessor() {
1569
1812
  // Run
1570
1813
  await sendData();
1571
1814
  await batchProcessor();
1815
+
1816
+ // Performance characteristics:
1817
+ // - Batch size 5000: ~100,000 messages/second
1818
+ // - Single DB transaction per batch (fetch + ack)
1819
+ // - Constant memory usage
1820
+ // - No performance degradation as queue grows
1572
1821
  ```
1573
1822
 
1574
1823
  ### Example 5: Scheduled Jobs
@@ -1886,33 +2135,34 @@ Apache License 2.0 - see [LICENSE.md](LICENSE.md) for details.
1886
2135
 
1887
2136
  ## 📈 Performance
1888
2137
 
1889
- **Benchmarks** (PostgreSQL 16, Node.js 22):
1890
- - **Throughput**: 10,000+ messages/second
2138
+ **Benchmarks** (PostgreSQL 16, Node.js 22, cursor-based consumption):
2139
+ - **Throughput**: 100,000+ messages/second with batch operations
1891
2140
  - **Latency**: < 10ms for immediate pop operations
2141
+ - **Constant-time consumption**: O(batch_size) regardless of queue depth
1892
2142
  - **Concurrent Connections**: 1,000+ long polling connections
1893
2143
  - **Database**: Optimized with proper indexing and connection pooling
1894
2144
 
1895
- **Optimization Features:**
2145
+ **Cursor-Based Architecture Benefits:**
2146
+ - **No performance degradation**: Consistent speed whether queue has 1K or 1B messages
2147
+ - **Predictable latency**: 150-200ms per batch throughout entire queue lifecycle
2148
+ - **Efficient batch processing**: Direct cursor access eliminates table scans
2149
+ - **Scalable to billions**: UUIDv7-based cursor positioning
2150
+
2151
+ **Additional Optimization Features:**
1896
2152
  - Connection pooling with configurable size
1897
2153
  - Resource caching for queue/partition lookups
1898
- - Batch operations for bulk inserts/updates
2154
+ - Batch operations for bulk inserts/updates (up to 10,000 messages per batch)
1899
2155
  - Optimized SQL queries with proper indexes
1900
2156
  - Event-driven architecture for minimal polling overhead
1901
2157
  - Long polling for real-time message delivery
2158
+ - SKIP LOCKED for lock-free concurrent consumption
1902
2159
 
1903
2160
  ---
1904
2161
 
1905
2162
  ## 🎯 Roadmap
1906
2163
 
1907
- - [ ] **Horizontal Scaling**: Better support for multiple server instances
1908
2164
  - [ ] **Message Scheduling**: Cron-like scheduling for recurring jobs
1909
- - [ ] **Priority Lanes**: Dynamic priority adjustment based on load
1910
- - [ ] **Metrics Export**: Prometheus/Grafana integration
1911
- - [ ] **Admin API**: REST API for queue management
1912
2165
  - [ ] **Client Libraries**: Python, Go, Java clients
1913
- - [ ] **Message Tracing**: Distributed tracing integration
1914
- - [ ] **Queue Templates**: Pre-configured queue patterns
1915
- - [ ] **GraphQL API**: Alternative to REST API
1916
2166
  - [ ] **Kubernetes Operator**: Native K8s support
1917
2167
 
1918
2168
  ---
@@ -1921,6 +2171,6 @@ Apache License 2.0 - see [LICENSE.md](LICENSE.md) for details.
1921
2171
 
1922
2172
  **Queen Message Queue System** - Built for performance, reliability, and developer happiness 🚀
1923
2173
 
1924
- Made with ❤️ by [Smartpricing](https://github.com/smartpricing)
2174
+ Made with ❤️ by [Smartness](https://github.com/smartpricing)
1925
2175
 
1926
2176
  </div>