290 lines
7.8 KiB
Markdown
290 lines
7.8 KiB
Markdown
# DLQ Non-Destructive Message Retrieval - Implementation Summary
|
|
|
|
**Date:** January 20, 2026
|
|
**Changes:** Queue-agnostic DLQ operations + RabbitMQ Management API integration
|
|
|
|
---
|
|
|
|
## ✅ What Was Fixed
|
|
|
|
### 1. **Non-Destructive Message Peeking** (`/api/dlq/:queueName/messages`)
|
|
|
|
**Exclusively uses RabbitMQ Management API for true non-destructive peeking.**
|
|
|
|
#### Implementation: Management API Only
|
|
```javascript
|
|
// POST http://localhost:15672/api/queues/%2f/queue_name/get
|
|
{
|
|
"count": 50,
|
|
"ackmode": "ack_requeue_true", // ← TRUE non-destructive peek
|
|
"encoding": "auto"
|
|
}
|
|
```
|
|
|
|
**Benefits:**
|
|
- ✅ **True peeking** - messages never leave queue
|
|
- ✅ **Order preserved** - no requeuing needed
|
|
- ✅ **No race conditions** - atomic operation
|
|
- ✅ **Multiple concurrent reads** - safe for simultaneous access
|
|
- ✅ **No fallback complexity** - single, reliable method
|
|
|
|
**Requirements:**
|
|
- RabbitMQ Management plugin enabled: `rabbitmq-plugins enable rabbitmq_management`
|
|
- Set `RABBITMQ_MGMT_ENABLED=true` in environment (default: true)
|
|
- Default port: 15672
|
|
|
|
**Error Handling:**
|
|
If Management API is not available, endpoint returns 503 error with clear message:
|
|
```json
|
|
{
|
|
"error": {
|
|
".tag": "unknown_app_error",
|
|
"message": "RabbitMQ Management API not available. Ensure plugin is enabled: rabbitmq-plugins enable rabbitmq_management"
|
|
}
|
|
}
|
|
```
|
|
|
|
**Response Format:**
|
|
```json
|
|
{
|
|
"messages": [
|
|
{
|
|
"position": 1,
|
|
"taskInfo": {...},
|
|
"errorMessage": "...",
|
|
"retryCount": 0,
|
|
"enqueuedAt": "2026-01-20T10:30:00Z",
|
|
"headers": {...},
|
|
"redelivered": false
|
|
}
|
|
],
|
|
"count": 3,
|
|
"queueName": "dev_partner_tasks_failed",
|
|
"method": "management-api"
|
|
}
|
|
```
|
|
|
|
**Note:** AMQP fallback has been removed. The endpoint now exclusively uses Management API for guaranteed non-destructive operation.
|
|
|
|
---
|
|
|
|
### 2. **Queue-Agnostic DLQ Operations**
|
|
|
|
**Fixed:** All retry operations now use standard `_failed` suffix (not `_dlq`)
|
|
|
|
#### Before (inconsistent):
|
|
```javascript
|
|
// ❌ Some used _dlq, some used _failed
|
|
const dlqName = `${queueName}_dlq`; // Wrong!
|
|
```
|
|
|
|
#### After (consistent):
|
|
```javascript
|
|
// ✅ All operations use _failed
|
|
const dlqName = `${queueName}_failed`; // Standard convention
|
|
```
|
|
|
|
**Endpoints Fixed:**
|
|
- ✅ `/api/dlq/:queueName/retryAll`
|
|
- ✅ `/api/dlq/:queueName/retryByPosition`
|
|
- ✅ `/api/dlq/:queueName/retryByHeader`
|
|
- ✅ `/api/dlq/:queueName/messages`
|
|
- ✅ `/api/dlq/:queueName/stats`
|
|
- ✅ `/api/dlq/:queueName/purge`
|
|
|
|
**Now works for ANY queue:**
|
|
```bash
|
|
# Partner tasks
|
|
curl http://localhost:4100/api/dlq/dev_partner_tasks/messages
|
|
|
|
# Job processing
|
|
curl http://localhost:4100/api/dlq/dev_jobs/messages
|
|
|
|
# Any custom queue
|
|
curl http://localhost:4100/api/dlq/my_custom_queue/messages
|
|
```
|
|
|
|
---
|
|
|
|
### 3. **RetryAll Improvements**
|
|
|
|
**What `/retryAll` Does:**
|
|
- Moves messages from DLQ back to main queue
|
|
- Adds retry metadata headers
|
|
- Processes up to `maxMessages` (default: 100)
|
|
|
|
**Response Format:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"processed": 42,
|
|
"retriedCount": 42, // Deprecated: use 'processed'
|
|
"queueName": "dev_partner_tasks",
|
|
"dlqName": "dev_partner_tasks_failed"
|
|
}
|
|
```
|
|
|
|
**Usage:**
|
|
```bash
|
|
# Retry all messages (up to 100)
|
|
curl -X POST http://localhost:4100/api/dlq/dev_partner_tasks/retryAll
|
|
|
|
# Retry specific count
|
|
curl -X POST http://localhost:4100/api/dlq/dev_partner_tasks/retryAll \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"maxMessages": 10}'
|
|
```
|
|
|
|
**Is it queue-agnostic?**
|
|
✅ **YES** - Works with ANY queue type:
|
|
- `dev_partner_tasks` → `dev_partner_tasks_failed`
|
|
- `dev_jobs` → `dev_jobs_failed`
|
|
- `notifications` → `notifications_failed`
|
|
- Any custom queue with `_failed` DLQ
|
|
|
|
---
|
|
|
|
## 📁 Files Modified
|
|
|
|
### Core Implementation
|
|
- **[controllers/dlq.js](controllers/dlq.js)** - Added Management API integration + fixed naming
|
|
- **[environment.env](environment.env)** - Added `RABBITMQ_MGMT_PORT` and `RABBITMQ_MGMT_ENABLED`
|
|
|
|
### Test Scripts
|
|
- **[tests/test_dlq_messages_direct.js](tests/test_dlq_messages_direct.js)** - Direct RabbitMQ test (proves bug + fix)
|
|
- **[tests/test_dlq_mgmt_api.js](tests/test_dlq_mgmt_api.js)** - Management API integration test
|
|
- **[tests/test_dlq_routes.js](tests/test_dlq_routes.js)** - Full API integration test
|
|
|
|
---
|
|
|
|
## 🧪 Testing
|
|
|
|
### Quick Test (No Auth Required)
|
|
```bash
|
|
# Demonstrates old bug vs new fix
|
|
node tests/test_dlq_messages_direct.js
|
|
|
|
# Test Management API integration
|
|
node tests/test_dlq_mgmt_api.js
|
|
```
|
|
|
|
### Full Integration Test (Requires Auth)
|
|
```bash
|
|
# Get admin token first, then:
|
|
node tests/test_dlq_routes.js --queue dev_partner_tasks --token YOUR_TOKEN
|
|
```
|
|
|
|
---
|
|
|
|
## 🔧 Configuration
|
|
|
|
### Enable Management API (Required)
|
|
|
|
**1. Enable plugin:**
|
|
```bash
|
|
rabbitmq-plugins enable rabbitmq_management
|
|
```
|
|
|
|
**2. Configure user permissions:**
|
|
|
|
RabbitMQ users need specific tags to access the Management API. The `agm` user needs the **`monitoring`** or **`management`** tag.
|
|
|
|
```bash
|
|
# Option A: Add monitoring tag (read-only access - RECOMMENDED)
|
|
rabbitmqctl set_user_tags agm monitoring
|
|
|
|
# Option B: Add management tag (full management access)
|
|
rabbitmqctl set_user_tags agm management
|
|
|
|
# Option C: Keep existing tags and add monitoring
|
|
rabbitmqctl set_user_tags agm monitoring policymaker
|
|
|
|
# Verify user tags
|
|
rabbitmqctl list_users
|
|
```
|
|
|
|
**User Tag Permissions:**
|
|
- **`monitoring`**: Can view queues, connections, channels (read-only) ✅ **Recommended for production**
|
|
- **`management`**: Full management access (create/delete queues, etc.)
|
|
- **`administrator`**: Full admin access (user management, vhosts, etc.)
|
|
|
|
**3. Set vhost permissions (if needed):**
|
|
```bash
|
|
# Ensure agm user has access to the vhost
|
|
rabbitmqctl set_permissions -p / agm ".*" ".*" ".*"
|
|
```
|
|
|
|
**4. Verify access:**
|
|
```bash
|
|
# Test authentication
|
|
curl -u agm:Ag@Rabbit2024 http://localhost:15672/api/overview
|
|
|
|
# Should return JSON with RabbitMQ cluster info
|
|
# If 401 error: user lacks Management API tags
|
|
# If connection refused: Management plugin not enabled
|
|
```
|
|
|
|
**5. Configure in environment:**
|
|
```env
|
|
RABBITMQ_MGMT_PORT=15672
|
|
RABBITMQ_MGMT_ENABLED=true # Default: true
|
|
```
|
|
|
|
**6. Restart server:**
|
|
```bash
|
|
node server.js
|
|
```
|
|
|
|
### Troubleshooting 401 Errors
|
|
|
|
**If you see 401 errors:**
|
|
```bash
|
|
# Check current user tags
|
|
rabbitmqctl list_users
|
|
# Output: agm [] ← No tags means no Management API access!
|
|
|
|
# Add monitoring tag
|
|
rabbitmqctl set_user_tags agm monitoring
|
|
|
|
# Verify
|
|
rabbitmqctl list_users
|
|
# Output: agm [monitoring] ← Now has access!
|
|
```
|
|
|
|
### Without Management API
|
|
Endpoint will return 503 error with instructions to enable the plugin. No fallback is provided to ensure truly non-destructive operation.
|
|
|
|
---
|
|
|
|
## 📊 Performance Comparison
|
|
|
|
| Method | Truly Non-Destructive? | Order Preserved? | Concurrent Safe? | Requires Plugin? | Status |
|
|
|--------|------------------------|------------------|------------------|------------------|--------|
|
|
| **Management API** | ✅ Yes | ✅ Yes | ✅ Yes | ⚠️ Yes | **ACTIVE** |
|
|
| **AMQP Batch** | ⚠️ Mostly | ❌ No | ⚠️ Risky | ✅ No | **REMOVED** |
|
|
| **Old AMQP Loop** | ❌ No | ❌ No | ❌ No | ✅ No | **REMOVED** |
|
|
|
|
---
|
|
|
|
## 🎯 Summary
|
|
|
|
### Problem → Solution
|
|
1. **Message Duplication** → Removed AMQP fallback entirely
|
|
2. **No True Peeking** → Exclusively use Management API
|
|
3. **Inconsistent Naming** → Standardized `_failed` suffix
|
|
4. **Not Queue-Agnostic** → Works with any queue type
|
|
|
|
### Key Takeaways
|
|
- ✅ `/messages` endpoint is now **truly non-destructive** (Management API only)
|
|
- ✅ All DLQ operations work with ANY queue type
|
|
- ✅ Clear error messages when Management API unavailable
|
|
- ✅ Test scripts prove correctness
|
|
- ✅ Simplified codebase (removed fallback complexity)
|
|
- ⚠️ **Breaking change**: Requires Management plugin enabled
|
|
|
|
### Next Steps
|
|
1. **Enable RabbitMQ Management plugin** (required)
|
|
2. Run test scripts to verify setup
|
|
3. Monitor DLQ operations via `/stats` endpoint
|
|
4. Use `/messages` for debugging without side effects
|