queen-mq 0.4.0 → 0.6.4

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 (47) hide show
  1. package/README.md +520 -273
  2. package/{client-js/client-v2 → client-v2}/Queen.js +38 -0
  3. package/{client-js/client-v2 → client-v2}/README.md +61 -8
  4. package/package.json +5 -8
  5. package/{client-js/test-v2 → test-v2}/GETTING_STARTED.md +27 -0
  6. package/test-v2/README_SUBSCRIPTION_TESTS.md +201 -0
  7. package/{client-js/test-v2 → test-v2}/consume.js +10 -0
  8. package/{client-js/test-v2 → test-v2}/dlq.js +1 -1
  9. package/{client-js/test-v2 → test-v2}/load.js +2 -0
  10. package/{client-js/test-v2 → test-v2}/subscription.js +198 -18
  11. package/{client-js/test-v2 → test-v2}/transaction.js +66 -4
  12. package/LICENSE.md +0 -202
  13. package/client-js/benchmark/consumer.js +0 -209
  14. package/client-js/benchmark/consumer_multi.js +0 -216
  15. package/client-js/benchmark/producer.js +0 -80
  16. package/client-js/benchmark/producer_multi.js +0 -115
  17. /package/{client-js/client-v2 → client-v2}/LOGGING.md +0 -0
  18. /package/{client-js/client-v2 → client-v2}/buffer/BufferManager.js +0 -0
  19. /package/{client-js/client-v2 → client-v2}/buffer/MessageBuffer.js +0 -0
  20. /package/{client-js/client-v2 → client-v2}/builders/QueueBuilder.js +0 -0
  21. /package/{client-js/client-v2 → client-v2}/builders/TransactionBuilder.js +0 -0
  22. /package/{client-js/client-v2 → client-v2}/consumer/ConsumerManager.js +0 -0
  23. /package/{client-js/client-v2 → client-v2}/http/HttpClient.js +0 -0
  24. /package/{client-js/client-v2 → client-v2}/http/LoadBalancer.js +0 -0
  25. /package/{client-js/client-v2 → client-v2}/index.js +0 -0
  26. /package/{client-js/client-v2 → client-v2}/stream/StreamBuilder.js +0 -0
  27. /package/{client-js/client-v2 → client-v2}/stream/StreamConsumer.js +0 -0
  28. /package/{client-js/client-v2 → client-v2}/stream/Window.js +0 -0
  29. /package/{client-js/client-v2 → client-v2}/utils/defaults.js +0 -0
  30. /package/{client-js/client-v2 → client-v2}/utils/logger.js +0 -0
  31. /package/{client-js/client-v2 → client-v2}/utils/validation.js +0 -0
  32. /package/{client-js/test-v2 → test-v2}/AI_TEST_SUMMARY.md +0 -0
  33. /package/{client-js/test-v2 → test-v2}/MAINTENANCE_TEST.md +0 -0
  34. /package/{client-js/test-v2 → test-v2}/ai_buffering.js +0 -0
  35. /package/{client-js/test-v2 → test-v2}/ai_error_handling.js +0 -0
  36. /package/{client-js/test-v2 → test-v2}/ai_lease_renewal.js +0 -0
  37. /package/{client-js/test-v2 → test-v2}/ai_mixed_scenarios.js +0 -0
  38. /package/{client-js/test-v2 → test-v2}/ai_priority.js +0 -0
  39. /package/{client-js/test-v2 → test-v2}/ai_resources.js +0 -0
  40. /package/{client-js/test-v2 → test-v2}/ai_ttl_retention.js +0 -0
  41. /package/{client-js/test-v2 → test-v2}/complete.js +0 -0
  42. /package/{client-js/test-v2 → test-v2}/maintenance.js +0 -0
  43. /package/{client-js/test-v2 → test-v2}/pop.js +0 -0
  44. /package/{client-js/test-v2 → test-v2}/push.js +0 -0
  45. /package/{client-js/test-v2 → test-v2}/queue.js +0 -0
  46. /package/{client-js/test-v2 → test-v2}/retention.js +0 -0
  47. /package/{client-js/test-v2 → test-v2}/run.js +0 -0
@@ -357,6 +357,44 @@ export class Queen {
357
357
  return stats
358
358
  }
359
359
 
360
+ // ===========================
361
+ // Consumer Group Management
362
+ // ===========================
363
+
364
+ /**
365
+ * Delete a consumer group and optionally its subscription metadata
366
+ * @param {string} consumerGroup - Consumer group name
367
+ * @param {boolean} deleteMetadata - Whether to delete subscription metadata (default: true)
368
+ * @returns {Promise<object>}
369
+ */
370
+ async deleteConsumerGroup(consumerGroup, deleteMetadata = true) {
371
+ logger.log('Queen.deleteConsumerGroup', { consumerGroup, deleteMetadata })
372
+
373
+ const url = `/api/v1/consumer-groups/${encodeURIComponent(consumerGroup)}?deleteMetadata=${deleteMetadata}`
374
+ const response = await this.#httpClient.delete(url)
375
+
376
+ logger.log('Queen.deleteConsumerGroup', { success: true, consumerGroup })
377
+ return response
378
+ }
379
+
380
+ /**
381
+ * Update subscription timestamp for a consumer group
382
+ * @param {string} consumerGroup - Consumer group name
383
+ * @param {string} timestamp - New subscription timestamp (ISO 8601)
384
+ * @returns {Promise<object>}
385
+ */
386
+ async updateConsumerGroupTimestamp(consumerGroup, timestamp) {
387
+ logger.log('Queen.updateConsumerGroupTimestamp', { consumerGroup, timestamp })
388
+
389
+ const url = `/api/v1/consumer-groups/${encodeURIComponent(consumerGroup)}/subscription`
390
+ const response = await this.#httpClient.post(url, {
391
+ subscriptionTimestamp: timestamp
392
+ })
393
+
394
+ logger.log('Queen.updateConsumerGroupTimestamp', { success: true, consumerGroup })
395
+ return response
396
+ }
397
+
360
398
  // ===========================
361
399
  // Streaming API
362
400
  // ===========================
@@ -370,12 +370,21 @@ await queen
370
370
  })
371
371
  ```
372
372
 
373
+ **Server Default:** The server can be configured to change this default behavior:
374
+ ```bash
375
+ # Make all new consumer groups skip history by default
376
+ export DEFAULT_SUBSCRIPTION_MODE="new"
377
+ ./bin/queen-server
378
+ ```
379
+
380
+ When `DEFAULT_SUBSCRIPTION_MODE="new"` is set, new consumer groups automatically skip historical messages unless you explicitly override with `.subscriptionMode('all')`.
381
+
373
382
  ### Subscription Mode: 'new'
374
383
 
375
- Skip all historical messages and only process messages that arrive **after** subscription:
384
+ Skip historical messages and process messages that arrive **near** subscription time:
376
385
 
377
386
  ```javascript
378
- // Only process NEW messages, skip historical backlog
387
+ // Process recent messages (not historical backlog)
379
388
  await queen
380
389
  .queue('events')
381
390
  .group('realtime-monitor')
@@ -386,9 +395,33 @@ await queen
386
395
  ```
387
396
 
388
397
  **What happens:**
389
- 1. Consumer subscribes at `T0`
390
- 2. All messages before `T0` are skipped
391
- 3. Only messages arriving after `T0` are processed
398
+ 1. Consumer makes first pop at `T0` (e.g., 10:00:00)
399
+ 2. Server records `subscription_timestamp = T0` in metadata table
400
+ 3. Only messages with `created_at > T0` are processed
401
+ 4. All historical messages are skipped
402
+
403
+ **How it ensures consistency across partitions:**
404
+
405
+ Queen tracks subscription time separately from partition-level cursors:
406
+
407
+ ```javascript
408
+ // Timeline:
409
+ 10:00:00 - First pop() call
410
+ → Metadata recorded: subscription_timestamp = 10:00:00
411
+
412
+ // Consumer processes partition P1 for 10 minutes
413
+
414
+ 10:10:00 - New partition P2 is created, messages arrive
415
+ 10:15:00 - Consumer discovers P2 via pop()
416
+ → Uses ORIGINAL subscription_timestamp (10:00:00)
417
+ → Messages from 10:10:00 are captured! ✓
418
+ ```
419
+
420
+ **Key benefits:**
421
+ - ✅ **Consistent**: All partitions use the same subscription timestamp
422
+ - ✅ **No skipping**: New partitions discovered later are processed correctly
423
+ - ✅ **True NEW semantics**: Only messages after first pop request
424
+ - ✅ **Works with wildcards**: Namespace/task filters maintain subscription time
392
425
 
393
426
  ### Subscription Mode: 'new-only'
394
427
 
@@ -497,11 +530,18 @@ await queen
497
530
  - Subsequent consumers in the same group inherit the same position
498
531
  - To change subscription mode, use a different group name
499
532
 
533
+ ⏰ **NEW mode subscription tracking:**
534
+ - NEW mode tracks when the consumer group **first subscribes** (first pop request)
535
+ - This subscription timestamp is used consistently across all partitions
536
+ - Ensures new partitions discovered later don't skip messages
537
+ - Stored in `consumer_groups_metadata` table on the server
538
+
500
539
  💡 **Best Practices:**
501
- - Use `'new'` for real-time monitoring and alerting
502
- - Use default (all) for batch processing and analytics
503
- - Use timestamps for replay/debugging scenarios
540
+ - Use `'new'` for real-time monitoring (skip historical backlog)
541
+ - Use default (all) for batch processing and full history replay
542
+ - Use timestamps for precise replay/debugging scenarios
504
543
  - Name groups descriptively based on their subscription mode
544
+ - Be aware that "NEW" means messages after the **first pop request**, not the first message arrival
505
545
 
506
546
  ---
507
547
 
@@ -1660,6 +1700,19 @@ const dlq = await queen.queue('q').dlq('consumer-group').limit(10).get()
1660
1700
  const dlq = await queen.queue('q').dlq().from('2025-01-01').to('2025-01-31').get()
1661
1701
  ```
1662
1702
 
1703
+ ### Consumer Group Management
1704
+
1705
+ ```javascript
1706
+ // Delete a consumer group (including metadata)
1707
+ await queen.deleteConsumerGroup('my-group')
1708
+
1709
+ // Delete consumer group but keep subscription metadata
1710
+ await queen.deleteConsumerGroup('my-group', false)
1711
+
1712
+ // Update subscription timestamp
1713
+ await queen.updateConsumerGroupTimestamp('my-group', '2025-11-10T10:00:00Z')
1714
+ ```
1715
+
1663
1716
  ### Shutdown
1664
1717
 
1665
1718
  ```javascript
package/package.json CHANGED
@@ -1,18 +1,15 @@
1
1
  {
2
2
  "name": "queen-mq",
3
- "version": "0.4.0",
3
+ "version": "0.6.4",
4
4
  "type": "module",
5
5
  "description": "High-performance C++ message queue backed by PostgreSQL",
6
- "main": "client-js/client-v2/index.js",
6
+ "main": "client-v2/index.js",
7
7
  "scripts": {
8
- "start": "./server/bin/queen-server",
9
- "build:webapp": "cd webapp && npm install && npm run build",
10
- "publish:public": "npm publish --access public",
11
- "test": "node client-js/test/test-new.js"
8
+ "test": "node test-v2/run.js human"
12
9
  },
13
10
  "files": [
14
- "client-js/",
15
- "LICENSE.md",
11
+ "client-v2/**/*",
12
+ "test-v2/**/*",
16
13
  "README.md"
17
14
  ],
18
15
  "dependencies": {
@@ -119,6 +119,33 @@ Make sure:
119
119
  3. ✅ Environment variables are set (if needed)
120
120
  4. ✅ No production data in test database
121
121
 
122
+ ## Testing with Different Server Configurations
123
+
124
+ ### Standard Configuration (Default)
125
+
126
+ Run server with default settings:
127
+ ```bash
128
+ ./bin/queen-server
129
+ node test-v2/run.js
130
+ ```
131
+
132
+ **Expected:** Consumer groups without explicit `.subscriptionMode()` process all historical messages.
133
+
134
+ ### With DEFAULT_SUBSCRIPTION_MODE="new"
135
+
136
+ Run server with "new" as default:
137
+ ```bash
138
+ DEFAULT_SUBSCRIPTION_MODE="new" ./bin/queen-server
139
+ node test-v2/run.js
140
+ ```
141
+
142
+ **Expected:**
143
+ - Tests with explicit `.subscriptionMode('new')` work the same
144
+ - Tests without explicit mode will skip historical messages
145
+ - `subscriptionModeServerDefault` test detects and reports server default
146
+
147
+ **All tests pass with both configurations!** The tests are designed to be agnostic to server defaults.
148
+
122
149
  ## Test Philosophy
123
150
 
124
151
  The AI-generated tests follow these principles:
@@ -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
+
@@ -371,6 +371,7 @@ export async function consumerGroup(client) {
371
371
 
372
372
  await client
373
373
  .queue('test-queue-v2-consume-group')
374
+ .subscriptionMode('from_beginning')
374
375
  .group('test-group-01')
375
376
  .batch(messagesToPush)
376
377
  .limit(1)
@@ -381,6 +382,7 @@ export async function consumerGroup(client) {
381
382
 
382
383
  await client
383
384
  .queue('test-queue-v2-consume-group')
385
+ .subscriptionMode('from_beginning')
384
386
  .group('test-group-02')
385
387
  .batch(messagesToPush)
386
388
  .limit(1)
@@ -414,6 +416,7 @@ export async function consumerGroupWithPartition(client) {
414
416
  await client
415
417
  .queue('test-queue-v2-consume-group-with-partition')
416
418
  .partition('test-partition-01')
419
+ .subscriptionMode('from_beginning')
417
420
  .group('test-group-01')
418
421
  .batch(messagesToPush)
419
422
  .limit(1)
@@ -425,6 +428,7 @@ export async function consumerGroupWithPartition(client) {
425
428
  await client
426
429
  .queue('test-queue-v2-consume-group-with-partition')
427
430
  .partition('test-partition-01')
431
+ .subscriptionMode('from_beginning')
428
432
  .group('test-group-02')
429
433
  .batch(messagesToPush)
430
434
  .limit(1)
@@ -462,6 +466,7 @@ export async function manualAck(client) {
462
466
  await client
463
467
  .queue('test-queue-v2-manual-ack')
464
468
  .concurrency(10)
469
+ .subscriptionMode('from_beginning')
465
470
  .batch(1000)
466
471
  .wait(false)
467
472
  .limit(1)
@@ -514,6 +519,7 @@ export async function retries(client) {
514
519
  await client
515
520
  .queue('test-queue-v2-retries')
516
521
  .concurrency(1)
522
+ .subscriptionMode('from_beginning')
517
523
  .batch(100)
518
524
  .wait(false)
519
525
  .limit(300) // Allow up to 300 messages (3 batches of 100)
@@ -554,6 +560,7 @@ export async function retriesConsumerGroup(client) {
554
560
  .queue('test-queue-v2-retries-consumer-group')
555
561
  .group('test-group-01')
556
562
  .concurrency(1)
563
+ .subscriptionMode('from_beginning')
557
564
  .batch(100)
558
565
  .wait(false)
559
566
  .limit(300) // Allow up to 300 messages (3 batches of 100)
@@ -574,6 +581,7 @@ export async function retriesConsumerGroup(client) {
574
581
  .queue('test-queue-v2-retries-consumer-group')
575
582
  .group('test-group-02')
576
583
  .concurrency(1)
584
+ .subscriptionMode('from_beginning')
577
585
  .batch(100)
578
586
  .wait(false)
579
587
  .limit(100) // Allow up to 300 messages (3 batches of 100)
@@ -607,6 +615,7 @@ export async function autoRenewLease(client) {
607
615
  .queue('test-queue-v2-auto-renew-lease')
608
616
  .batch(1)
609
617
  .wait(false)
618
+ .subscriptionMode('from_beginning')
610
619
  .limit(1)
611
620
  .each()
612
621
  .consume(async msg => {
@@ -633,6 +642,7 @@ export async function autoRenewLease(client) {
633
642
  await client
634
643
  .queue('test-queue-v2-auto-renew-lease')
635
644
  .batch(1)
645
+ .subscriptionMode('from_beginning')
636
646
  .wait(false)
637
647
  .limit(1)
638
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)