π NestJS Microservices with RabbitMQ, Retries & DLQ β Production Setup That Actually Scales
β Stop building fragile microservices that silently fail.
β Start building systems that retry, recover, and scale automatically.
If you're using NestJS and not handling failures, retries, and dead-letter queues (DLQ) properly⦠your system will break in production. Period.
In this guide, Iβll show you a battle-tested architecture using NestJS + RabbitMQ with:
- π Retries
- π Dead Letter Queues (DLQ)
- β‘ Event-driven communication
- π§± Scalable microservices
π§ What Youβll Build
A real-world system with services like:
- authentication
- rbac
- quotation
- packages
- generate-quotation-pdf
- generate-quotation-ai
- subscription-plans
- user-subscriptions
- notifications
- send-otp
ποΈ Architecture Overview
API Gateway β RabbitMQ β Microservices (Consumers)
π No direct service-to-service calls
π Fully async & decoupled
π Monorepo Structure
nestjs-microservices/
β
βββ apps/
β βββ api-gateway/
β βββ authentication/
β βββ rbac/
β βββ quotation/
β βββ packages/
β βββ generate-quotation-pdf/
β βββ generate-quotation-ai/
β βββ subscription-plans/
β βββ user-subscriptions/
β βββ notifications/
β βββ send-otp/
β
βββ libs/
β βββ rabbitmq/
β βββ common/
β βββ dto/
β βββ config/
β βββ utils/
π Clean separation = easy scaling
π‘ Messaging Setup (Core Idea)
Instead of this β
await this.authService.validateUser();
We do this β
this.client.send('auth.validate', payload);
π Async, scalable, resilient
βοΈ RabbitMQ Configuration (DLQ + Retry)
ClientsModule.register([
{
name: 'RABBITMQ_SERVICE',
transport: Transport.RMQ,
options: {
urls: [process.env.RABBITMQ_URL],
queue: 'main_queue',
queueOptions: {
durable: true,
deadLetterExchange: 'dlx',
deadLetterRoutingKey: 'dlq',
},
},
},
]);
π Retry Mechanism (The Secret Sauce)
Main Queue β Retry Queue (TTL) β Main Queue β DLQ
Retry Queue Example:
{
queue: 'quotation_retry',
queueOptions: {
messageTtl: 5000,
deadLetterRoutingKey: 'quotation_queue',
},
}
π If a job fails β wait 5s β retry automatically
π Dead Letter Queue (DLQ)
When retries fail:
@EventPattern('quotation.dlq')
handleFailed(data: any) {
console.error('DLQ Message:', data);
}
π No silent failures anymore π₯
π€ Producer Example
@Injectable()
export class QuotationProducer {
constructor(@Inject('RABBITMQ_SERVICE') private client: ClientProxy) {}
createQuotation(data: any) {
return this.client.emit('quotation.create', data);
}
}
π₯ Consumer Example
@EventPattern('quotation.create')
async handle(data: any, context: RmqContext) {
const channel = context.getChannelRef();
const message = context.getMessage();
try {
await this.service.process(data);
channel.ack(message);
} catch (e) {
channel.nack(message, false, false); // goes to DLQ
}
}
β‘ Event-Driven Wins
| Traditional API | Event-Driven |
|---|---|
| Tight coupling β | Loose coupling β |
| Blocking β | Async β |
| Hard to scale β | Horizontally scalable β |
π₯ Real Use Cases
- π© send-otp β async SMS
- π generate-quotation-pdf β heavy processing
- π€ generate-quotation-ai β AI calls
- π notifications β emails, push
π Your API stays FAST β‘
π§ Production Best Practices
- β Use idempotency keys
- β Add correlation IDs
- β Monitor DLQ actively
- β Scale consumers independently
- β Separate queues per service
- β Validate DTOs strictly
π³ Bonus: Run Everything with Docker
rabbitmq:
image: rabbitmq:3-management
ports:
- "5672:5672"
- "15672:15672"
π Access dashboard β http://localhost:15672
π£ Hard Truth
If your system doesnβt handle failureβ¦ itβs already broken.
π Final Takeaway
Build microservices that donβt just βworkββ¦ but recover, retry, and scale automatically.
π§ TL;DR
- Use NestJS + RabbitMQ
- Prefer event-driven architecture
- Implement retries + DLQ
- Scale consumers independently
- Never ignore failures
π₯ Want More?
If this helped you, I can next show:
- βΈοΈ Kubernetes deployment (auto-scaling microservices)
- π Monitoring with Prometheus + Grafana
- π Full auth + API Gateway setup
Just comment: βPART 2β π
Top comments (0)