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.
Files changed (90) hide show
  1. package/API.md +1116 -0
  2. package/CACHE.md +519 -0
  3. package/DASHBOARD-V3.md +478 -0
  4. package/DASHBOARD.md +382 -0
  5. package/MOD_QUEUE.md +453 -0
  6. package/PARTITION_LOCKING_DESIGN.md +989 -0
  7. package/PLAN.md +707 -0
  8. package/QUERY_ANALSYS.md +72 -0
  9. package/QUEUE_BUS.md +334 -0
  10. package/README.md +1495 -0
  11. package/V2-PLAN.md +236 -0
  12. package/assets/dashboard.png +0 -0
  13. package/dashboard/.vscode/extensions.json +3 -0
  14. package/dashboard/README.md +5 -0
  15. package/dashboard/index.html +14 -0
  16. package/dashboard/package-lock.json +1458 -0
  17. package/dashboard/package.json +25 -0
  18. package/dashboard/public/vite.svg +1 -0
  19. package/dashboard/src/App.vue +29 -0
  20. package/dashboard/src/assets/styles/main.css +908 -0
  21. package/dashboard/src/assets/vue.svg +1 -0
  22. package/dashboard/src/components/cards/MetricCard.vue +298 -0
  23. package/dashboard/src/components/charts/QueueDepthChart.vue +276 -0
  24. package/dashboard/src/components/charts/QueueLagChart.vue +436 -0
  25. package/dashboard/src/components/charts/ThroughputChart.vue +302 -0
  26. package/dashboard/src/components/common/ActivityFeed.vue +251 -0
  27. package/dashboard/src/components/layout/AppHeader.vue +208 -0
  28. package/dashboard/src/components/layout/AppLayout.vue +88 -0
  29. package/dashboard/src/components/layout/AppSidebar.vue +261 -0
  30. package/dashboard/src/main.js +44 -0
  31. package/dashboard/src/router.js +54 -0
  32. package/dashboard/src/services/api.js +187 -0
  33. package/dashboard/src/services/websocket.js +167 -0
  34. package/dashboard/src/utils/constants.js +56 -0
  35. package/dashboard/src/utils/helpers.js +118 -0
  36. package/dashboard/src/views/Analytics.vue +912 -0
  37. package/dashboard/src/views/Dashboard.vue +906 -0
  38. package/dashboard/src/views/Messages.vue +437 -0
  39. package/dashboard/src/views/QueueDetail.vue +501 -0
  40. package/dashboard/src/views/Queues.vue +333 -0
  41. package/dashboard/vite.config.js +30 -0
  42. package/debug-namespace.js +110 -0
  43. package/docs/long-polling.md +159 -0
  44. package/docs/multi-server-cache-solutions.md +185 -0
  45. package/docs/performance-tuning.md +222 -0
  46. package/examples/bus-mode.js +239 -0
  47. package/examples/continuous-consumer-optimized.js +215 -0
  48. package/examples/continuous-consumer.js +159 -0
  49. package/examples/continuous-producer.js +343 -0
  50. package/examples/mixed-mode.js +277 -0
  51. package/examples/multi-server-test.js +305 -0
  52. package/examples/single.js +64 -0
  53. package/examples/smartchat-dealyed.js +42 -0
  54. package/examples/smartchat.js +52 -0
  55. package/examples/test-cache-invalidation.js +119 -0
  56. package/examples/test-cache-multi-server.js +245 -0
  57. package/examples/test-minimal-client.js +112 -0
  58. package/examples/test-queue-creation-policy.js +137 -0
  59. package/init-db.js +20 -0
  60. package/package.json +36 -0
  61. package/src/client/client.js +291 -0
  62. package/src/client/index.js +6 -0
  63. package/src/client/queenClient.js +513 -0
  64. package/src/client/utils/http.js +172 -0
  65. package/src/client/utils/loadBalancer.js +152 -0
  66. package/src/client/utils/retry.js +35 -0
  67. package/src/config.js +215 -0
  68. package/src/database/connection.js +103 -0
  69. package/src/database/poolManager.js +192 -0
  70. package/src/database/schema-v2.sql +214 -0
  71. package/src/managers/eventManager.js +59 -0
  72. package/src/managers/queueManagerOptimized.js +1512 -0
  73. package/src/managers/resourceCache.js +96 -0
  74. package/src/managers/systemEventManager.js +127 -0
  75. package/src/routes/ack.js +26 -0
  76. package/src/routes/analytics.js +812 -0
  77. package/src/routes/configure.js +46 -0
  78. package/src/routes/messages.js +298 -0
  79. package/src/routes/pop.js +85 -0
  80. package/src/routes/push.js +28 -0
  81. package/src/routes/resources.js +296 -0
  82. package/src/server.js +1286 -0
  83. package/src/services/encryptionService.js +82 -0
  84. package/src/services/evictionService.js +131 -0
  85. package/src/services/retentionService.js +129 -0
  86. package/src/services/startupSync.js +35 -0
  87. package/src/test/test.js +4521 -0
  88. package/src/utils/logger.js +44 -0
  89. package/src/utils/uuid.js +5 -0
  90. package/src/websocket/wsServer.js +221 -0
@@ -0,0 +1,72 @@
1
+ ### Query Analysis and Improvement Plan
2
+
3
+ This document outlines the planned changes to improve SQL safety, correctness, FIFO guarantees, duplicate-avoidance, and performance.
4
+
5
+ ## Goals
6
+ - Enforce per-partition FIFO even when no partition is specified.
7
+ - Prevent duplicate message selection across workers.
8
+ - Harden transactions against injection and long blocks.
9
+ - Reduce planner anti-patterns; improve query efficiency.
10
+ - Align retention/eviction with schema v2 semantics.
11
+
12
+ ## Changes and Why
13
+
14
+ 1) Security and transaction hardening
15
+ - What: Whitelist transaction isolation levels in `withTransaction` (no dynamic interpolation).
16
+ - Why: Avoids SQL injection risk and invalid isolation values.
17
+
18
+ - What: Set `statement_timeout` and `lock_timeout` via `SET LOCAL` at transaction start.
19
+ - Why: Prevents long blocking operations and stuck workers under contention.
20
+
21
+ - What: Add retry for serialization failures (SQLSTATE 40001) and deadlocks (40P01) in the query wrapper.
22
+ - Why: These are expected under high contention; bounded retry improves resiliency.
23
+
24
+ 2) Strict FIFO when partition is unspecified
25
+ - What: Partition-first selection in queue-mode and namespace/task pop paths; lock the chosen partition, then fetch only from that partition ordered by `created_at ASC`.
26
+ - Why: Guarantees FIFO per partition and eliminates mixed-partition batches.
27
+
28
+ - What: Add fairness heuristic for choosing the partition (e.g., partition with the oldest pending message or least recent `last_activity`).
29
+ - Why: Prevents starvation and balances throughput without breaking FIFO.
30
+
31
+ 3) Availability predicate simplification
32
+ - What: Replace `LEFT JOIN messages_status ... WHERE (ms.id IS NULL OR ms.status IN (...))` with `NOT EXISTS`/UNION.
33
+ - Why: Removes OR conditions that block index use; produces better plans.
34
+
35
+ - What: Precompute per-queue time thresholds (delayed_processing, max_wait_time, window_buffer) in a small CTE.
36
+ - Why: Avoids non-sargable predicates involving NOW() and enables index range scans on `created_at`.
37
+
38
+ 4) Pop query shaping
39
+ - What: Eliminate correlated subselects in `RETURNING` by projecting needed columns in the CTE and returning them directly.
40
+ - Why: Avoids per-row subqueries; simpler and faster.
41
+
42
+ - What: Keep `FOR UPDATE OF m SKIP LOCKED` in queue-mode pops.
43
+ - Why: Ensures a message is only claimed by one worker in competing consumer mode.
44
+
45
+ 5) Bus-mode (consumer groups)
46
+ - What: Use `ON CONFLICT DO NOTHING` (or update) when inserting into `messages_status`.
47
+ - Why: Handles races on `(message_id, consumer_group)` without surfacing errors; maintains single-delivery per group.
48
+
49
+ 6) API pagination
50
+ - What: Implement keyset (cursor) pagination for `listMessages` while preserving offset for backward compatibility.
51
+ - Why: OFFSET is O(n) at high pages; keyset keeps scans bounded and stable using `(created_at, id)`.
52
+
53
+ 7) Retention and eviction
54
+ - What: Align `retentionService` with schema v2: delete only when configured to do so; rely on cascade for statuses.
55
+ - Why: Prevents unintended loss of unprocessed messages; keeps behavior explicit.
56
+
57
+ - What: Keep eviction as status transitions (e.g., `evicted`) and log counts to retention history.
58
+ - Why: Avoids destructive deletes while signaling expired messages.
59
+
60
+ 8) Tests
61
+ - What: Add/adjust tests for single-partition FIFO (when partition unspecified), no duplicates under concurrency (queue/bus), keyset pagination, and retention/eviction behavior.
62
+ - Why: Prevent regressions and validate concurrency semantics.
63
+
64
+ ## Rollout Order
65
+ 1. Transaction hardening (whitelist isolation, timeouts) and retry policy.
66
+ 2. Partition-first pop logic (queue-mode, namespace/task) with fairness.
67
+ 3. Availability predicate rewrite and time-threshold precompute.
68
+ 4. Pop `RETURNING` cleanup (remove correlated subselects).
69
+ 5. Bus-mode conflict handling with ON CONFLICT.
70
+ 6. Keyset pagination for `listMessages`.
71
+ 7. Retention adjustments.
72
+ 8. Tests and docs.
package/QUEUE_BUS.md ADDED
@@ -0,0 +1,334 @@
1
+ # Queue/Bus Mode Implementation Plan
2
+
3
+ ## Overview
4
+ Implement dynamic queue/bus mode based on consumer group parameter, allowing the same queue to serve both competing consumers (queue mode) and broadcast to multiple consumer groups (bus mode).
5
+
6
+ ## Core Concept
7
+ - **Queue Mode**: No `consumerGroup` specified → competing consumers (traditional queue behavior)
8
+ - **Bus Mode**: `consumerGroup` specified → each consumer group gets all messages (pub/sub behavior)
9
+ - **Mixed Mode**: Same queue can serve both patterns simultaneously
10
+
11
+ ## Architecture Changes
12
+
13
+ ### 1. Database Schema Changes (`src/database/schema-v2.sql`)
14
+
15
+ #### 1.1 Modify Messages Table
16
+ - Remove all status-related fields from `queen.messages`
17
+ - Keep only: `id`, `transaction_id`, `partition_id`, `payload`, `created_at`, `is_encrypted`
18
+ - Keep `transaction_id` in messages table (set during push, immutable)
19
+
20
+ #### 1.2 Create Messages Status Table
21
+ ```sql
22
+ CREATE TABLE queen.messages_status (
23
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
24
+ message_id UUID REFERENCES queen.messages(id) ON DELETE CASCADE,
25
+ consumer_group VARCHAR(255), -- NULL for queue mode
26
+ status VARCHAR(20) DEFAULT 'pending',
27
+ worker_id VARCHAR(255),
28
+ locked_at TIMESTAMP,
29
+ completed_at TIMESTAMP,
30
+ failed_at TIMESTAMP,
31
+ error_message TEXT,
32
+ retry_count INTEGER DEFAULT 0,
33
+ lease_expires_at TIMESTAMP,
34
+ processing_at TIMESTAMP,
35
+ created_at TIMESTAMP DEFAULT NOW(),
36
+ UNIQUE(message_id, consumer_group)
37
+ );
38
+ ```
39
+
40
+ #### 1.3 Consumer Group Registry (Optional)
41
+ ```sql
42
+ CREATE TABLE queen.consumer_groups (
43
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
44
+ queue_id UUID REFERENCES queen.queues(id) ON DELETE CASCADE,
45
+ name VARCHAR(255) NOT NULL,
46
+ created_at TIMESTAMP DEFAULT NOW(),
47
+ subscription_start_from TIMESTAMP, -- NULL = consume all, timestamp = consume from this point
48
+ active BOOLEAN DEFAULT true,
49
+ UNIQUE(queue_id, name)
50
+ );
51
+ ```
52
+
53
+ #### 1.3 Create Optimized Indexes
54
+ - Index for queue mode lookups (consumer_group IS NULL)
55
+ - Index for bus mode lookups (consumer_group IS NOT NULL)
56
+ - Composite indexes for efficient pop operations
57
+ - Indexes for lease expiration checks
58
+
59
+ ### 2. Consumer Group Subscription Strategies
60
+
61
+ #### Option 1: Consume All Messages (Default)
62
+ - New consumer groups start from the beginning
63
+ - Process all existing messages in the queue
64
+ - Good for: Analytics, audit logs, data replication
65
+
66
+ #### Option 2: Consume From Subscription Time
67
+ - New consumer groups only see messages created after subscription
68
+ - Skip all historical messages
69
+ - Good for: Real-time notifications, monitoring
70
+
71
+ #### Option 3: Consume From Specific Time
72
+ - Consumer group specifies a start timestamp
73
+ - Process messages from that point forward
74
+ - Good for: Replay scenarios, recovery
75
+
76
+ #### Implementation Approach:
77
+ ```javascript
78
+ // Option 1: Consume all (default)
79
+ client.pop({
80
+ queue: 'events',
81
+ consumerGroup: 'analytics'
82
+ });
83
+
84
+ // Option 2: From subscription time
85
+ client.pop({
86
+ queue: 'events',
87
+ consumerGroup: 'notifications',
88
+ subscriptionMode: 'new' // Only new messages
89
+ });
90
+
91
+ // Option 3: From specific time
92
+ client.pop({
93
+ queue: 'events',
94
+ consumerGroup: 'replay',
95
+ subscriptionFrom: '2024-01-01T00:00:00Z'
96
+ });
97
+ ```
98
+
99
+ #### Database Implementation:
100
+ ```sql
101
+ -- When popping with a new consumer group:
102
+ -- 1. Check if consumer group exists in registry
103
+ -- 2. If not, create it with subscription preferences
104
+ -- 3. Only return messages based on subscription_start_from
105
+
106
+ -- For "new only" mode:
107
+ INSERT INTO queen.consumer_groups (queue_id, name, subscription_start_from)
108
+ VALUES ($1, $2, NOW());
109
+
110
+ -- For "all messages" mode:
111
+ INSERT INTO queen.consumer_groups (queue_id, name, subscription_start_from)
112
+ VALUES ($1, $2, NULL); -- NULL means consume all
113
+
114
+ -- Pop query considers subscription time:
115
+ SELECT m.* FROM queen.messages m
116
+ WHERE m.partition_id = $1
117
+ AND NOT EXISTS (
118
+ SELECT 1 FROM queen.messages_status ms
119
+ WHERE ms.message_id = m.id
120
+ AND ms.consumer_group = $2
121
+ )
122
+ AND m.created_at >= COALESCE(
123
+ (SELECT subscription_start_from
124
+ FROM queen.consumer_groups
125
+ WHERE queue_id = $3 AND name = $2),
126
+ '1970-01-01'::timestamp -- If NULL, consume all
127
+ )
128
+ ORDER BY m.created_at ASC
129
+ LIMIT $4;
130
+ ```
131
+
132
+ ### 3. Backend Changes
133
+
134
+ #### 3.1 Queue Manager (`src/managers/queueManagerOptimized.js`)
135
+
136
+ ##### Push Messages
137
+ - Keep existing behavior: generate transaction_id during push
138
+ - Only insert into messages table (no status entry)
139
+ - Transaction_id remains in messages table (immutable)
140
+
141
+ ##### Pop Messages
142
+ - **Queue Mode Logic** (no consumer group):
143
+ ```javascript
144
+ // 1. Find messages without status OR with pending status where consumer_group IS NULL
145
+ // 2. Create/update status entry with consumer_group = NULL
146
+ // 3. Mark as processing with lease
147
+ // 4. Return messages
148
+ ```
149
+
150
+ - **Bus Mode Logic** (with consumer group):
151
+ ```javascript
152
+ // 1. Find messages without status entry for this specific consumer_group
153
+ // 2. Create status entry for this consumer_group
154
+ // 3. Mark as processing with lease
155
+ // 4. Return messages
156
+ ```
157
+
158
+ ##### Acknowledge Messages
159
+ - Update status for specific consumer_group (or NULL)
160
+ - In bus mode, message stays available for other consumer groups
161
+ - In queue mode, message is done after single acknowledgment
162
+
163
+ ##### Reclaim Leases
164
+ - Check lease expiration per consumer_group
165
+ - Reset to pending for that specific consumer_group only
166
+
167
+ #### 3.2 Pop Route (`src/routes/pop.js`)
168
+ - Accept optional `consumerGroup` parameter
169
+ - Pass through to queue manager
170
+
171
+ #### 3.3 Server Routes (`src/server.js`)
172
+ - Update pop endpoint to accept consumer_group query parameter
173
+ - Ensure backward compatibility (no consumer_group = queue mode)
174
+
175
+ ### 4. Client SDK Changes (`src/client/queenClient.js`)
176
+
177
+ #### 4.1 Pop Method
178
+ ```javascript
179
+ pop({ queue, partition, consumerGroup, wait, timeout, batch })
180
+ ```
181
+
182
+ #### 4.2 Consume Method
183
+ ```javascript
184
+ consume({ queue, partition, consumerGroup, handler, options })
185
+ ```
186
+
187
+ #### 4.3 Documentation
188
+ - Add consumer group examples
189
+ - Document queue vs bus mode behavior
190
+
191
+ ### 5. Testing (`src/test/test.js`)
192
+
193
+ #### 5.1 Queue Mode Tests
194
+ - Test competing consumers (no consumer group)
195
+ - Verify only one consumer gets each message
196
+ - Test acknowledgment completes message
197
+
198
+ #### 5.2 Bus Mode Tests
199
+ - Test multiple consumer groups
200
+ - Verify all groups get all messages
201
+ - Test independent acknowledgment per group
202
+ - Test consumer group isolation
203
+
204
+ #### 5.3 Mixed Mode Tests
205
+ - Test same queue with both modes simultaneously
206
+ - Verify queue mode consumers compete
207
+ - Verify bus mode consumers all receive messages
208
+
209
+ #### 5.4 Edge Cases
210
+ - Test consumer group with special characters
211
+ - Test very long consumer group names
212
+ - Test lease expiration per consumer group
213
+ - Test retry logic per consumer group
214
+
215
+ ### 6. Examples
216
+
217
+ #### 6.1 Create Bus Mode Example (`examples/bus-mode.js`)
218
+ - Demonstrate multiple consumer groups
219
+ - Show independent progress tracking
220
+ - Compare with queue mode
221
+
222
+ #### 6.2 Create Mixed Mode Example (`examples/mixed-mode.js`)
223
+ - Same queue, different consumption patterns
224
+ - Workers + Analytics + Notifications
225
+
226
+ ### 7. Documentation Updates
227
+
228
+ #### 7.1 README.md
229
+ - Add Bus Mode section
230
+ - Document consumer groups
231
+ - Add comparison with Kafka
232
+ - Update API reference
233
+
234
+ #### 7.2 API.md
235
+ - Document consumer_group parameter
236
+ - Add bus mode examples
237
+
238
+ ## Implementation Steps
239
+
240
+ ### Phase 1: Database Schema
241
+ 1. Backup existing schema
242
+ 2. Modify `schema-v2.sql` with new structure
243
+ 3. Drop and recreate database:
244
+ ```bash
245
+ nvm use 22 && node init-db.js
246
+ ```
247
+
248
+ ### Phase 2: Backend Core
249
+ 1. Update queue manager push logic
250
+ 2. Implement dual-mode pop logic
251
+ 3. Update acknowledgment logic
252
+ 4. Update lease reclaim logic
253
+ 5. Test with basic operations
254
+
255
+ ### Phase 3: API Layer
256
+ 1. Update pop route to accept consumer_group
257
+ 2. Update server endpoints
258
+ 3. Ensure backward compatibility
259
+ 4. Test API endpoints
260
+
261
+ ### Phase 4: Client SDK
262
+ 1. Add consumerGroup parameter to pop
263
+ 2. Update consume method
264
+ 3. Add TypeScript types (if applicable)
265
+ 4. Test client operations
266
+
267
+ ### Phase 5: Testing
268
+ 1. Write comprehensive test suite
269
+ 2. Test queue mode (backward compatibility)
270
+ 3. Test bus mode (new functionality)
271
+ 4. Test mixed mode scenarios
272
+ 5. Performance testing
273
+
274
+ ### Phase 6: Examples & Documentation
275
+ 1. Create example scripts
276
+ 2. Update README
277
+ 3. Update API documentation
278
+ 4. Create migration guide
279
+
280
+ ## Testing Commands
281
+
282
+ ```bash
283
+ # Reinitialize database
284
+ nvm use 22 && node init-db.js
285
+
286
+ # Start server
287
+ nvm use 22 && npm start
288
+
289
+ # Run tests
290
+ nvm use 22 && node src/test/test.js
291
+
292
+ # Test bus mode
293
+ nvm use 22 && node examples/bus-mode.js
294
+
295
+ # Test mixed mode
296
+ nvm use 22 && node examples/mixed-mode.js
297
+ ```
298
+
299
+ ## Performance Considerations
300
+
301
+ ### Optimizations
302
+ 1. Use partial indexes for NULL/NOT NULL consumer_group
303
+ 2. Batch status insertions for bus mode
304
+ 3. Consider materialized views for message counts
305
+ 4. Add connection pooling per consumer group
306
+
307
+ ### Monitoring
308
+ 1. Track consumer group lag
309
+ 2. Monitor status table growth
310
+ 3. Add metrics for queue vs bus mode usage
311
+ 4. Dashboard updates for consumer groups
312
+
313
+ ## Rollback Plan
314
+ 1. Keep backup of original schema
315
+ 2. Maintain backward compatibility
316
+ 3. Feature flag for bus mode (optional)
317
+ 4. Gradual rollout strategy
318
+
319
+ ## Success Criteria
320
+ - [ ] All existing tests pass (backward compatibility)
321
+ - [ ] Queue mode works as before
322
+ - [ ] Bus mode delivers to all consumer groups
323
+ - [ ] Mixed mode works correctly
324
+ - [ ] Performance remains acceptable
325
+ - [ ] Documentation is complete
326
+ - [ ] Examples demonstrate all patterns
327
+
328
+ ## Notes
329
+ - Consumer group = NULL is special case for queue mode
330
+ - Transaction ID moves to status table
331
+ - Messages table becomes immutable after insert
332
+ - Status table handles all mutable state
333
+ - Consider TTL for old status entries
334
+ - Add cleanup job for completed messages in bus mode