Successfully implemented HTTP endpoints for DLQ management, enabling operators to trigger replay operations without shell access to pods.
-
src/api/controllers/dlq.controller.tsPOST /admin/dlq/replay- Triggers async replayGET /admin/dlq/status- Returns DLQ metrics- Protected by
ApiKeyGuard - Tracks last replay job metadata in-memory
-
src/api/controllers/dto/dlq.dto.tsDlqReplayRequestDto- Request body with optionalids[]DlqReplayResponseDto- 202 response withjobIdDlqStatusResponseDto- Status response with depth and replay stats
-
src/api/controllers/dlq.controller.spec.ts- Unit tests for controller methods
- Mocked service dependencies
- Tests for both replay modes (all vs specific IDs)
-
src/test/integration/dlq-api.integration.spec.ts- Integration tests against real Postgres database
- Tests 5+ scenarios:
- Replay all entries
- Replay with ledger range filtering
- Skip non-retryable entries
- Handle failed replays with retry count increment
- Dry-run mode verification
- Uses testcontainers for isolated database
docs/DLQ_API.md- Complete API reference
- Authentication guide
- Usage patterns (monitoring, CI/CD, K8s CronJob)
- Security considerations
- Comparison with CLI tool
src/api/api.module.ts- Added
IngestorModuleimport (providesDlqService) - Added
DeadLetterEventEntityto TypeORM features - Registered
DlqController
- Added
┌─────────────────────────────────────────────────┐
│ HTTP Client (curl, K8s CronJob, CI/CD) │
└───────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ DlqController │
│ ├─ POST /admin/dlq/replay → 202 Accepted │
│ └─ GET /admin/dlq/status → 200 OK │
│ │
│ Protected by ApiKeyGuard │
└───────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ DlqService │
│ ├─ replayAll(options) │
│ ├─ count() │
│ └─ Existing DLQ logic (from CLI) │
└───────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ DeadLetterEventEntity (Postgres) │
└─────────────────────────────────────────────────┘
✅ POST /admin/dlq/replay triggers processing of all failed events
- Endpoint implemented with async execution
- Returns 202 Accepted with job ID
- Supports both "replay all" and "replay specific IDs" modes
✅ GET /admin/dlq/status returns metrics
- Returns
{ depth: number, lastReplayAt: ISO8601, lastReplayCount: number } - Depth is real-time count from database
- Last replay metadata tracked in-memory per controller instance
✅ Integration test seeds 5 events and replays via endpoint
- Comprehensive integration test suite with 5+ test cases
- Tests against real Postgres database using testcontainers
- Verifies:
- Replay of all entries
- Ledger range filtering
- Non-retryable entry skipping
- Failed replay handling
- Dry-run mode
curl -X POST http://localhost:3000/admin/dlq/replay \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{}'
# Response:
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"message": "Replay started for all eligible DLQ entries"
}curl -X POST http://localhost:3000/admin/dlq/replay \
-H "x-api-key: YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"ids": ["uuid1", "uuid2", "uuid3"]}'
# Response:
{
"jobId": "550e8400-e29b-41d4-a716-446655440000",
"message": "Replay started for 3 specific entries"
}curl http://localhost:3000/admin/dlq/status \
-H "x-api-key: YOUR_KEY"
# Response:
{
"depth": 42,
"lastReplayAt": "2024-01-15T10:30:00.000Z",
"lastReplayCount": 15
}- Authentication: API key via
x-api-keyheader (configured viaINTERNAL_API_KEYenv var) - Guard: Reuses existing
ApiKeyGuardfrom other admin endpoints - Logging: All operations logged with job IDs for audit trail
cd indexer
npm test -- dlq.controller.speccd indexer
npm run test:integration -- dlq-api.integration.spec- Environment Variable: Ensure
INTERNAL_API_KEYis set in production - Network Access: Configure ingress/firewall rules to restrict admin endpoint access
- Monitoring: Monitor
/admin/dlq/statusendpoint for DLQ depth alerts - Automation: Consider setting up K8s CronJob for periodic replay (see docs/DLQ_API.md)
- Job Status Tracking: Currently only stores last job; could implement persistent job queue
- Dry-Run via API: Add query parameter
?dryRun=trueto preview replay without execution - Webhooks: Notify external systems on replay completion
- Rate Limiting: Add throttling to prevent replay abuse
- Granular ID Replay: Optimize ID-based replay to avoid ledger-range approach
| Feature | CLI (dlq:replay) |
HTTP API |
|---|---|---|
| Shell access | Required | Not required |
| K8s friendly | ❌ Needs kubectl exec |
✅ Standard HTTP |
| Async execution | ❌ Blocking | ✅ Non-blocking (202) |
| Automation | Limited | Easy (curl, CI/CD) |
| Auth | Container access | API key |
| Status tracking | N/A | /status endpoint |
- Existing DLQ logic:
src/ingestor/dlq.service.ts - CLI tool:
src/cli/dlq-replay.command.ts - Entity:
src/database/entities/dead-letter-event.entity.ts - API guard:
src/api/api-key.guard.ts