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.
- package/README.md +520 -273
- package/{client-js/client-v2 → client-v2}/Queen.js +38 -0
- package/{client-js/client-v2 → client-v2}/README.md +61 -8
- package/package.json +5 -8
- package/{client-js/test-v2 → test-v2}/GETTING_STARTED.md +27 -0
- package/test-v2/README_SUBSCRIPTION_TESTS.md +201 -0
- package/{client-js/test-v2 → test-v2}/consume.js +10 -0
- package/{client-js/test-v2 → test-v2}/dlq.js +1 -1
- package/{client-js/test-v2 → test-v2}/load.js +2 -0
- package/{client-js/test-v2 → test-v2}/subscription.js +198 -18
- package/{client-js/test-v2 → test-v2}/transaction.js +66 -4
- package/LICENSE.md +0 -202
- package/client-js/benchmark/consumer.js +0 -209
- package/client-js/benchmark/consumer_multi.js +0 -216
- package/client-js/benchmark/producer.js +0 -80
- package/client-js/benchmark/producer_multi.js +0 -115
- /package/{client-js/client-v2 → client-v2}/LOGGING.md +0 -0
- /package/{client-js/client-v2 → client-v2}/buffer/BufferManager.js +0 -0
- /package/{client-js/client-v2 → client-v2}/buffer/MessageBuffer.js +0 -0
- /package/{client-js/client-v2 → client-v2}/builders/QueueBuilder.js +0 -0
- /package/{client-js/client-v2 → client-v2}/builders/TransactionBuilder.js +0 -0
- /package/{client-js/client-v2 → client-v2}/consumer/ConsumerManager.js +0 -0
- /package/{client-js/client-v2 → client-v2}/http/HttpClient.js +0 -0
- /package/{client-js/client-v2 → client-v2}/http/LoadBalancer.js +0 -0
- /package/{client-js/client-v2 → client-v2}/index.js +0 -0
- /package/{client-js/client-v2 → client-v2}/stream/StreamBuilder.js +0 -0
- /package/{client-js/client-v2 → client-v2}/stream/StreamConsumer.js +0 -0
- /package/{client-js/client-v2 → client-v2}/stream/Window.js +0 -0
- /package/{client-js/client-v2 → client-v2}/utils/defaults.js +0 -0
- /package/{client-js/client-v2 → client-v2}/utils/logger.js +0 -0
- /package/{client-js/client-v2 → client-v2}/utils/validation.js +0 -0
- /package/{client-js/test-v2 → test-v2}/AI_TEST_SUMMARY.md +0 -0
- /package/{client-js/test-v2 → test-v2}/MAINTENANCE_TEST.md +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_buffering.js +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_error_handling.js +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_lease_renewal.js +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_mixed_scenarios.js +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_priority.js +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_resources.js +0 -0
- /package/{client-js/test-v2 → test-v2}/ai_ttl_retention.js +0 -0
- /package/{client-js/test-v2 → test-v2}/complete.js +0 -0
- /package/{client-js/test-v2 → test-v2}/maintenance.js +0 -0
- /package/{client-js/test-v2 → test-v2}/pop.js +0 -0
- /package/{client-js/test-v2 → test-v2}/push.js +0 -0
- /package/{client-js/test-v2 → test-v2}/queue.js +0 -0
- /package/{client-js/test-v2 → test-v2}/retention.js +0 -0
- /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
|
|
384
|
+
Skip historical messages and process messages that arrive **near** subscription time:
|
|
376
385
|
|
|
377
386
|
```javascript
|
|
378
|
-
//
|
|
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
|
|
390
|
-
2.
|
|
391
|
-
3. Only messages
|
|
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
|
|
502
|
-
- Use default (all) for batch processing and
|
|
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
|
|
3
|
+
"version": "0.6.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "High-performance C++ message queue backed by PostgreSQL",
|
|
6
|
-
"main": "client-
|
|
6
|
+
"main": "client-v2/index.js",
|
|
7
7
|
"scripts": {
|
|
8
|
-
"
|
|
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-
|
|
15
|
-
"
|
|
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(
|
|
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)
|