queen-mq 0.3.1 โ†’ 0.6.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 (45) hide show
  1. package/README.md +309 -167
  2. package/client-js/client-v2/Queen.js +66 -0
  3. package/client-js/client-v2/README.md +67 -10
  4. package/client-js/client-v2/builders/QueueBuilder.js +7 -1
  5. package/client-js/client-v2/builders/TransactionBuilder.js +20 -4
  6. package/client-js/client-v2/stream/StreamBuilder.js +72 -0
  7. package/client-js/client-v2/stream/StreamConsumer.js +156 -0
  8. package/client-js/client-v2/stream/Window.js +140 -0
  9. package/client-js/test-v2/GETTING_STARTED.md +27 -0
  10. package/client-js/test-v2/MAINTENANCE_TEST.md +148 -0
  11. package/client-js/test-v2/README_SUBSCRIPTION_TESTS.md +201 -0
  12. package/client-js/test-v2/consume.js +11 -0
  13. package/client-js/test-v2/dlq.js +1 -1
  14. package/client-js/test-v2/load.js +2 -0
  15. package/client-js/test-v2/maintenance.js +261 -0
  16. package/client-js/test-v2/retention.js +69 -0
  17. package/client-js/test-v2/run.js +7 -1
  18. package/client-js/test-v2/subscription.js +198 -18
  19. package/client-js/test-v2/transaction.js +66 -4
  20. package/package.json +2 -2
  21. package/client-js/client/client.js +0 -1536
  22. package/client-js/client/index.js +0 -4
  23. package/client-js/client/utils/http.js +0 -173
  24. package/client-js/client/utils/loadBalancer.js +0 -152
  25. package/client-js/client/utils/retry.js +0 -41
  26. package/client-js/services/encryptionService.js +0 -82
  27. package/client-js/services/evictionService.js +0 -160
  28. package/client-js/services/retentionService.js +0 -162
  29. package/client-js/services/startupSync.js +0 -35
  30. package/client-js/test/README.md +0 -224
  31. package/client-js/test/advanced-client-tests.js +0 -761
  32. package/client-js/test/advanced-pattern-tests.js +0 -1137
  33. package/client-js/test/bus-mode-tests.js +0 -361
  34. package/client-js/test/core-tests.js +0 -457
  35. package/client-js/test/edge-case-tests.js +0 -562
  36. package/client-js/test/enterprise-tests.js +0 -637
  37. package/client-js/test/human.js +0 -162
  38. package/client-js/test/partition-locking-tests.js +0 -545
  39. package/client-js/test/partition-transaction-tests.js +0 -482
  40. package/client-js/test/qos0-tests.js +0 -334
  41. package/client-js/test/test-new.js +0 -370
  42. package/client-js/test/utils.js +0 -169
  43. package/client-js/test/window-buffer-test.js +0 -114
  44. package/client-js/utils/logger.js +0 -44
  45. package/client-js/utils/uuid.js +0 -5
@@ -0,0 +1,148 @@
1
+ # Maintenance Mode Test
2
+
3
+ ## Overview
4
+
5
+ Comprehensive test for the maintenance mode feature with file buffer.
6
+
7
+ ## Test Scenario
8
+
9
+ 1. **Start consumer** - Begins consuming messages from queue
10
+ 2. **Start producer** - Produces 10 messages/second
11
+ 3. **Enable maintenance** - Triggers maintenance mode via API
12
+ 4. **Verify buffering** - Consumer stops receiving (messages go to file buffer)
13
+ 5. **Continue producing** - Producer keeps running for 10 seconds during maintenance
14
+ 6. **Disable maintenance** - Deactivates maintenance mode via API
15
+ 7. **Verify drain** - Consumer resumes receiving messages
16
+ 8. **Stop producer** - Halts message production
17
+ 9. **Wait for completion** - Waits 10 seconds for file buffer to drain
18
+ 10. **Verify counts** - Ensures all produced messages were received
19
+
20
+ ## Running the Test
21
+
22
+ ### Standalone
23
+
24
+ ```bash
25
+ cd /Users/alice/Work/queen/client-js/test-v2
26
+ node maintenance.js
27
+ ```
28
+
29
+ ### Via Test Runner
30
+
31
+ ```bash
32
+ # Run just this test
33
+ node run.js test_maintenance_mode
34
+
35
+ # Run all human tests (includes this one)
36
+ node run.js human
37
+
38
+ # Run all tests
39
+ node run.js
40
+ ```
41
+
42
+ ## Expected Output
43
+
44
+ ```
45
+ ๐Ÿงช Testing Maintenance Mode with File Buffer
46
+
47
+ ๐Ÿ“‹ Step 1: Configuring queue "test-maintenance-queue"...
48
+ โœ… Queue configured
49
+
50
+ ๐Ÿ“ฅ Step 2: Starting consumer...
51
+ โœ… Consumer started
52
+
53
+ ๐Ÿ“ค Step 3: Starting producer (10 msgs/sec)...
54
+ โœ… Producer started
55
+
56
+ โฑ๏ธ Step 4: Waiting 3 seconds for normal message flow...
57
+ ๐Ÿ“จ Received 10 messages (total: 10)
58
+ ๐Ÿ“จ Received 10 messages (total: 20)
59
+ ๐Ÿ“จ Received 10 messages (total: 30)
60
+ Produced: 30, Received: 30
61
+
62
+ ๐Ÿ”ง Step 5: Enabling MAINTENANCE MODE...
63
+ Response: { maintenanceMode: true, bufferedMessages: 0, ... }
64
+ โœ… Maintenance mode enabled
65
+
66
+ โฑ๏ธ Step 6: Waiting 2 seconds - consumer should stop receiving...
67
+ Messages received during maintenance: 0
68
+ Total: Produced=50, Received=30
69
+
70
+ โฑ๏ธ Step 7: Producing during maintenance for 10 seconds...
71
+ (Messages should go to file buffer)
72
+
73
+ Maintenance period complete:
74
+ - Total produced: 150
75
+ - Total received: 30
76
+ - Buffered (should be ~100): 120
77
+
78
+ ๐Ÿ“Š Step 8: Checking maintenance status...
79
+ Status: { maintenanceMode: true, bufferedMessages: 120, ... }
80
+
81
+ โœ… Step 9: Disabling MAINTENANCE MODE...
82
+ Response: { maintenanceMode: false, bufferedMessages: 120, ... }
83
+ (File buffer should start draining to database)
84
+
85
+ โฑ๏ธ Step 10: Waiting for messages to resume...
86
+ ๐Ÿ“จ Received 10 messages (total: 40)
87
+ Messages received after resuming: 10
88
+ โœ… Messages are flowing again!
89
+
90
+ ๐Ÿ›‘ Step 11: Stopping producer...
91
+ Final produced count: 150
92
+
93
+ โฑ๏ธ Step 12: Waiting 10 seconds for file buffer to drain...
94
+ 1s - Received: 50/150 (33.3%)
95
+ ๐Ÿ“จ Received 10 messages (total: 60)
96
+ 2s - Received: 70/150 (46.7%)
97
+ ๐Ÿ“จ Received 10 messages (total: 80)
98
+ 3s - Received: 90/150 (60.0%)
99
+ ๐Ÿ“จ Received 10 messages (total: 100)
100
+ 4s - Received: 110/150 (73.3%)
101
+ ๐Ÿ“จ Received 10 messages (total: 120)
102
+ 5s - Received: 130/150 (86.7%)
103
+ ๐Ÿ“จ Received 10 messages (total: 140)
104
+ 6s - Received: 150/150 (100.0%)
105
+ โœ… All messages received!
106
+
107
+ ๐Ÿ›‘ Step 13: Stopping consumer...
108
+ โœ… Consumer stopped
109
+
110
+ ๐Ÿ“Š Final Verification:
111
+
112
+ Total Produced: 150
113
+ Total Received: 150
114
+ Difference: 0
115
+
116
+ โœ… SUCCESS: All messages accounted for!
117
+ Maintenance mode works correctly with file buffer.
118
+
119
+ ๐Ÿ‘‹ Queen client closed
120
+
121
+ โœ… All tests passed!
122
+ ```
123
+
124
+ ## What It Tests
125
+
126
+ โœ… **Maintenance mode activation** - API responds correctly
127
+ โœ… **Message buffering** - Messages go to file buffer (consumer stops receiving)
128
+ โœ… **Continued production** - Can push messages during maintenance
129
+ โœ… **Maintenance mode deactivation** - API responds correctly
130
+ โœ… **Automatic drain** - File buffer drains to database
131
+ โœ… **Message ordering** - All messages received in order (FIFO)
132
+ โœ… **No message loss** - Produced count == Received count
133
+ โœ… **Multi-instance support** - Uses database for state (works across restarts)
134
+
135
+ ## Success Criteria
136
+
137
+ - All produced messages are eventually received
138
+ - Consumer stops receiving during maintenance
139
+ - Consumer resumes receiving after maintenance is disabled
140
+ - No duplicates or lost messages
141
+ - Drain completes within 10 seconds
142
+
143
+ ## Notes
144
+
145
+ - Uses `axios` for direct API calls (maintenance endpoints)
146
+ - Uses Queen client for queue operations (push/pop/ack)
147
+ - Test takes ~25 seconds total (3s warmup + 10s maintenance + 10s drain)
148
+
@@ -0,0 +1,201 @@
1
+ # Subscription Mode Tests
2
+
3
+ Tests for consumer group subscription modes, compatible with any server `DEFAULT_SUBSCRIPTION_MODE` configuration.
4
+
5
+ ## Test Overview
6
+
7
+ | Test Function | Description | Explicit Mode Used |
8
+ |--------------|-------------|-------------------|
9
+ | `subscriptionModeNew` | Validates `.subscriptionMode('new')` skips historical messages | Yes (`new`) |
10
+ | `subscriptionModeNewOnly` | Validates alias `.subscriptionMode('new-only')` | Yes (`new-only`) |
11
+ | `subscriptionFromNow` | Validates `.subscriptionFrom('now')` | Yes (`now`) |
12
+ | `subscriptionFromTimestamp` | Validates timestamp-based subscription | Yes (timestamp) |
13
+ | `subscriptionModeAll` | Tests default behavior (depends on server config) | Mixed |
14
+ | `subscriptionModeServerDefault` | **NEW:** Detects and validates server default | Mixed |
15
+
16
+ ## Running the Tests
17
+
18
+ ### Run all subscription tests:
19
+ ```bash
20
+ cd client-js/test-v2
21
+ node run.js subscription
22
+ ```
23
+
24
+ ### Run specific subscription test:
25
+ ```bash
26
+ node run.js subscriptionModeNew
27
+ node run.js subscriptionModeServerDefault
28
+ ```
29
+
30
+ ## Server Configuration Compatibility
31
+
32
+ These tests work with **any** server `DEFAULT_SUBSCRIPTION_MODE` configuration:
33
+
34
+ ### Configuration 1: Standard (Default)
35
+
36
+ ```bash
37
+ # Start server without default
38
+ ./bin/queen-server
39
+
40
+ # Run tests
41
+ node run.js subscription
42
+ ```
43
+
44
+ **Expected Behavior:**
45
+ - Consumer groups without explicit mode process all historical messages
46
+ - Consumer groups with `.subscriptionMode('new')` skip history
47
+ - `subscriptionModeServerDefault` reports: "all (or empty string)"
48
+
49
+ ### Configuration 2: With DEFAULT_SUBSCRIPTION_MODE="new"
50
+
51
+ ```bash
52
+ # Start server with "new" as default
53
+ DEFAULT_SUBSCRIPTION_MODE="new" ./bin/queen-server
54
+
55
+ # Run tests
56
+ node run.js subscription
57
+ ```
58
+
59
+ **Expected Behavior:**
60
+ - Consumer groups without explicit mode skip historical messages
61
+ - Consumer groups with `.subscriptionMode('new')` skip history (same)
62
+ - `subscriptionModeServerDefault` reports: "new"
63
+
64
+ **โœ… All tests pass with both configurations!**
65
+
66
+ ## Test Details
67
+
68
+ ### subscriptionModeNew
69
+
70
+ Tests the explicit `.subscriptionMode('new')` behavior:
71
+
72
+ 1. Pushes 5 historical messages
73
+ 2. Creates two consumer groups:
74
+ - One without explicit mode (behavior depends on server)
75
+ - One with `.subscriptionMode('new')` (always skips)
76
+ 3. Verifies the `new` mode group gets 0 historical messages
77
+ 4. Pushes 3 new messages
78
+ 5. Verifies both groups get the new messages
79
+
80
+ **Key Assertion:** `.subscriptionMode('new')` always skips historical messages.
81
+
82
+ ### subscriptionModeServerDefault (NEW)
83
+
84
+ Detects and validates the server's default subscription mode:
85
+
86
+ 1. Pushes historical messages
87
+ 2. Creates consumer group WITHOUT explicit subscription mode
88
+ 3. Detects server default based on behavior:
89
+ - Got historical messages โ†’ server default is "all"
90
+ - Got 0 messages โ†’ server default is "new"
91
+ 4. Validates explicit `.subscriptionMode('new')` still works
92
+ 5. Verifies new messages are received by both groups
93
+
94
+ **Key Assertion:** Server default affects groups without explicit mode, but explicit modes always work.
95
+
96
+ ### subscriptionFromTimestamp
97
+
98
+ Tests timestamp-based subscription:
99
+
100
+ 1. Pushes "first batch" of messages
101
+ 2. Records cutoff timestamp
102
+ 3. Pushes "second batch" of messages
103
+ 4. Creates consumer group with `.subscriptionFrom(cutoffTimestamp)`
104
+ 5. Verifies only messages after timestamp are received
105
+
106
+ **Note:** Timestamp precision may vary based on database clock.
107
+
108
+ ## Common Issues
109
+
110
+ ### Issue: Test fails with "expected X, got Y"
111
+
112
+ **Cause:** Server has different default than test expects.
113
+
114
+ **Solution:** Check server configuration:
115
+ ```bash
116
+ # Check if DEFAULT_SUBSCRIPTION_MODE is set
117
+ echo $DEFAULT_SUBSCRIPTION_MODE
118
+
119
+ # Check server logs on startup
120
+ LOG_LEVEL=debug ./bin/queen-server | grep "default subscription"
121
+ ```
122
+
123
+ ### Issue: Consumer group exists from previous run
124
+
125
+ **Cause:** Consumer groups persist between test runs.
126
+
127
+ **Solution:** The test runner cleans up test data automatically:
128
+ ```javascript
129
+ await dbPool.query(`DELETE FROM queen.queues WHERE name LIKE 'test-%'`)
130
+ ```
131
+
132
+ Or manually:
133
+ ```sql
134
+ DELETE FROM queen.partition_consumers
135
+ WHERE consumer_group LIKE 'group-%';
136
+ ```
137
+
138
+ ### Issue: Timing-related test failures
139
+
140
+ **Cause:** Messages not fully persisted before consumption.
141
+
142
+ **Solution:** Tests include appropriate delays. If still failing, increase delays:
143
+ ```javascript
144
+ await new Promise(resolve => setTimeout(resolve, 500)) // Increase if needed
145
+ ```
146
+
147
+ ## Adding New Subscription Tests
148
+
149
+ When adding new subscription mode tests:
150
+
151
+ 1. **Use unique queue/group names** to avoid conflicts
152
+ 2. **Be explicit about subscription modes** in test assertions
153
+ 3. **Document expected behavior** for both server configurations
154
+ 4. **Use descriptive group names** like `group-explicit-new` vs `group-default`
155
+
156
+ Example:
157
+ ```javascript
158
+ export async function testNewFeature(client) {
159
+ // Setup
160
+ await client.queue('test-new-feature').create()
161
+
162
+ // Test explicit behavior (works with any server default)
163
+ const result = await client
164
+ .queue('test-new-feature')
165
+ .group('group-explicit-new')
166
+ .subscriptionMode('new') // Explicit!
167
+ .pop()
168
+
169
+ // Assert based on explicit mode, not server default
170
+ // ...
171
+ }
172
+ ```
173
+
174
+ ## Debugging Failed Tests
175
+
176
+ Enable detailed logging:
177
+
178
+ ```bash
179
+ # Client logging
180
+ QUEEN_CLIENT_LOG=true node run.js subscriptionModeNew
181
+
182
+ # Server logging
183
+ LOG_LEVEL=debug ./bin/queen-server
184
+ ```
185
+
186
+ Look for these log lines:
187
+ ```
188
+ Consumer group 'group-xxx' exists: false, has subscription options: true
189
+ Subscription mode 'new' - starting from latest message: <uuid>
190
+ Applying default subscription mode 'new' for consumer group 'group-yyy'
191
+ ```
192
+
193
+ ## Summary
194
+
195
+ - โœ… Tests work with any `DEFAULT_SUBSCRIPTION_MODE` configuration
196
+ - โœ… Explicit subscription modes are always tested and validated
197
+ - โœ… Server default behavior is detected and reported
198
+ - โœ… All tests are documented and maintainable
199
+
200
+ Run the tests and see them pass! ๐ŸŽ‰
201
+
@@ -190,6 +190,7 @@ export async function testConsumerOrdering(client) {
190
190
  await client
191
191
  .queue('test-queue-v2-consume-batch')
192
192
  .push([{ data: { id: i } }])
193
+ console.log(new Date().toISOString(), 'Pushed message:', i)
193
194
  }
194
195
 
195
196
 
@@ -370,6 +371,7 @@ export async function consumerGroup(client) {
370
371
 
371
372
  await client
372
373
  .queue('test-queue-v2-consume-group')
374
+ .subscriptionMode('from_beginning')
373
375
  .group('test-group-01')
374
376
  .batch(messagesToPush)
375
377
  .limit(1)
@@ -380,6 +382,7 @@ export async function consumerGroup(client) {
380
382
 
381
383
  await client
382
384
  .queue('test-queue-v2-consume-group')
385
+ .subscriptionMode('from_beginning')
383
386
  .group('test-group-02')
384
387
  .batch(messagesToPush)
385
388
  .limit(1)
@@ -413,6 +416,7 @@ export async function consumerGroupWithPartition(client) {
413
416
  await client
414
417
  .queue('test-queue-v2-consume-group-with-partition')
415
418
  .partition('test-partition-01')
419
+ .subscriptionMode('from_beginning')
416
420
  .group('test-group-01')
417
421
  .batch(messagesToPush)
418
422
  .limit(1)
@@ -424,6 +428,7 @@ export async function consumerGroupWithPartition(client) {
424
428
  await client
425
429
  .queue('test-queue-v2-consume-group-with-partition')
426
430
  .partition('test-partition-01')
431
+ .subscriptionMode('from_beginning')
427
432
  .group('test-group-02')
428
433
  .batch(messagesToPush)
429
434
  .limit(1)
@@ -461,6 +466,7 @@ export async function manualAck(client) {
461
466
  await client
462
467
  .queue('test-queue-v2-manual-ack')
463
468
  .concurrency(10)
469
+ .subscriptionMode('from_beginning')
464
470
  .batch(1000)
465
471
  .wait(false)
466
472
  .limit(1)
@@ -513,6 +519,7 @@ export async function retries(client) {
513
519
  await client
514
520
  .queue('test-queue-v2-retries')
515
521
  .concurrency(1)
522
+ .subscriptionMode('from_beginning')
516
523
  .batch(100)
517
524
  .wait(false)
518
525
  .limit(300) // Allow up to 300 messages (3 batches of 100)
@@ -553,6 +560,7 @@ export async function retriesConsumerGroup(client) {
553
560
  .queue('test-queue-v2-retries-consumer-group')
554
561
  .group('test-group-01')
555
562
  .concurrency(1)
563
+ .subscriptionMode('from_beginning')
556
564
  .batch(100)
557
565
  .wait(false)
558
566
  .limit(300) // Allow up to 300 messages (3 batches of 100)
@@ -573,6 +581,7 @@ export async function retriesConsumerGroup(client) {
573
581
  .queue('test-queue-v2-retries-consumer-group')
574
582
  .group('test-group-02')
575
583
  .concurrency(1)
584
+ .subscriptionMode('from_beginning')
576
585
  .batch(100)
577
586
  .wait(false)
578
587
  .limit(100) // Allow up to 300 messages (3 batches of 100)
@@ -606,6 +615,7 @@ export async function autoRenewLease(client) {
606
615
  .queue('test-queue-v2-auto-renew-lease')
607
616
  .batch(1)
608
617
  .wait(false)
618
+ .subscriptionMode('from_beginning')
609
619
  .limit(1)
610
620
  .each()
611
621
  .consume(async msg => {
@@ -632,6 +642,7 @@ export async function autoRenewLease(client) {
632
642
  await client
633
643
  .queue('test-queue-v2-auto-renew-lease')
634
644
  .batch(1)
645
+ .subscriptionMode('from_beginning')
635
646
  .wait(false)
636
647
  .limit(1)
637
648
  .renewLease(true, 1000)
@@ -25,7 +25,7 @@ export async function testDLQ(client) {
25
25
  .queue(queueName)
26
26
  .batch(1)
27
27
  .wait(false)
28
- .limit(1) // Process up to 2 messages (original + retry)
28
+ .limit(2) // Process up to 2 messages (original + retry)
29
29
  .each()
30
30
  .consume(async msg => {
31
31
  // Always fail to trigger DLQ
@@ -129,6 +129,7 @@ export async function testLoadConsumerGroup(client) {
129
129
  await client
130
130
  .queue('test-queue-v2-load-consumer-group')
131
131
  .group('test-consumer-group-a')
132
+ .subscriptionMode('from_beginning')
132
133
  .concurrency(10)
133
134
  .batch(10000)
134
135
  .wait(false)
@@ -153,6 +154,7 @@ export async function testLoadConsumerGroup(client) {
153
154
  await client
154
155
  .queue('test-queue-v2-load-consumer-group')
155
156
  .group('test-consumer-group-b')
157
+ .subscriptionMode('from_beginning')
156
158
  .concurrency(10)
157
159
  .batch(10000)
158
160
  .wait(false)