BullMQ memiliki lebih dari 4,4 juta unduhan npm mingguan — angka yang mencerminkan betapa banyak developer Node.js menjangkau antrian berbasis Redis sebelum mempertimbangkan message broker mandiri seperti RabbitMQ. Keduanya adalah alat yang sangat baik, dan saya telah menggunakan keduanya dalam produksi. Untuk ERP Commsult Indonesia, saya menggunakan BullMQ untuk menangani notifikasi email dan pekerjaan pembuatan invoice — itu adalah pilihan yang tepat untuk beban kerja tersebut.
BullMQ adalah pustaka antrian Node.js yang dibangun di atas Redis. Ini menyediakan antrian pekerjaan dengan prioritas, pekerjaan tertunda, pekerjaan berulang (gaya cron), kontrol konkurensi, pembatasan laju, dan dashboard (Bull Board) untuk pemantauan. Karena berjalan di Redis, yang kemungkinan sudah ada di stack Anda untuk caching, BullMQ tidak menambahkan ketergantungan infrastruktur baru.
Dalam otomasi email ERP kami, event invoice.paid memicu pekerjaan BullMQ yang menghasilkan PDF tanda terima dan mengirim email konfirmasi. Kami menggunakan tiga fitur antrian: prioritas pekerjaan, pekerjaan tertunda (jadwalkan email tindak lanjut 7 hari setelah pembuatan invoice), dan percobaan ulang pekerjaan dengan backoff eksponensial. Bull Board memberi tim keuangan visibilitas ke dalam pekerjaan yang tertunda dan gagal tanpa memerlukan akses database.
BullMQ vs RabbitMQ — When to Use Which
BullMQ (Redis-backed Job Queue)
─────────────────────────────────────────────────────────
NestJS Service ──► Redis ──► BullMQ Worker (NestJS)
│
Job States:
waiting → active → completed
└─► failed → DLQ
Use for: Background jobs, scheduled tasks, retry logic
Ecosystem: Node.js only | Dashboard: Bull Board UI
─────────────────────────────────────────────────────────
RabbitMQ (AMQP Message Broker)
─────────────────────────────────────────────────────────
┌─── Direct Exchange ──► Queue A (NestJS)
Producer ──► Exchange ┤
(Any lang) ├─── Topic Exchange ──► Queue B (Python)
└─── Fanout Exchange ──► Queue C (Java)
Use for: Cross-language, complex routing, shared infra
Features: Dead Letter Exchange, Per-queue TTL, PriorityDari membangun otomasi email di ERP kami: atur batas maxAttempts pada setiap pekerjaan — jangan biarkan di default percobaan ulang tanpa batas. Payload pekerjaan yang salah bentuk yang selalu melempar akan menumpuk percobaan ulang selamanya, mengonsumsi memori dan CPU Redis. Juga beri nama antrian Anda secara deskriptif ('erp:invoice:email', 'erp:report:generation') daripada 'default' — ketika Anda melihat kunci Redis enam bulan kemudian, Anda akan langsung memahami untuk apa setiap antrian itu.
RabbitMQ adalah message broker mandiri yang mengimplementasikan AMQP (Advanced Message Queuing Protocol). Ini mendukung exchange, antrian, binding, kunci routing, dan beberapa jenis exchange (direct, fanout, topic, headers). Tidak seperti BullMQ, RabbitMQ adalah bahasa-agnostik — produsen dan consumer dapat ditulis dalam bahasa apa pun. RabbitMQ adalah pilihan yang tepat ketika Anda membutuhkan message passing lintas bahasa atau ketika message broker Anda adalah komponen infrastruktur bersama yang digunakan oleh beberapa tim dan layanan.
// BullMQ setup with NestJS
// app.module.ts
import { BullModule } from '@nestjs/bullmq';
@Module({
imports: [
BullModule.forRoot({ connection: { host: 'localhost', port: 6379 } }),
BullModule.registerQueue(
{ name: 'erp:invoice:email' },
{ name: 'erp:report:generation' },
),
],
})
export class AppModule {}
// invoice-email.processor.ts
@Processor('erp:invoice:email')
export class InvoiceEmailProcessor {
@Process()
async handleInvoiceEmail(job: Job<InvoiceEmailPayload>) {
await this.emailService.sendInvoice(job.data);
}
}
// invoice.service.ts — Adding jobs to the queue
@Injectable()
export class InvoiceService {
constructor(
@InjectQueue('erp:invoice:email') private emailQueue: Queue,
) {}
async markPaid(invoiceId: string) {
await this.repo.update(invoiceId, { status: 'paid' });
await this.emailQueue.add(
'send-receipt',
{ invoiceId },
{
attempts: 3, // max retries
backoff: { type: 'exponential', delay: 2000 },
removeOnComplete: 100, // keep last 100 completed
removeOnFail: 200, // keep last 200 failed for inspection
}
);
}
}Model routing RabbitMQ lebih fleksibel daripada antrian sederhana BullMQ. Exchange Direct merutekan pesan ke antrian berdasarkan kecocokan kunci routing yang tepat. Exchange Topic merutekan berdasarkan pola kunci routing ('order.#' cocok dengan 'order.created', 'order.paid', 'order.cancelled'). Exchange Fanout menyiarkan ke semua antrian yang terikat — berguna untuk fan-out event ketika beberapa layanan membutuhkan setiap event.
Kesalahan umum dengan RabbitMQ adalah lupa mengakui pesan. Secara default, RabbitMQ menandai pesan sebagai terkirim segera setelah dikirim ke consumer — jika consumer crash sebelum memprosesnya, pesan hilang. Selalu gunakan acknowledgment manual (ack setelah pemrosesan berhasil) dan konfigurasi publisher confirms di sisi produsen. Juga, antrian RabbitMQ terbatas — jika consumer Anda lebih lambat dari produsen dan Anda belum menetapkan panjang antrian maksimum, Anda akan menghabiskan memori.
NestJS mendukung keduanya secara langsung. Untuk BullMQ, gunakan @nestjs/bullmq — daftarkan antrian dengan BullModule.registerQueue(), dekorasi prosesor dengan @Processor dan @Process. Untuk RabbitMQ, gunakan @nestjs/microservices dengan transport AMQP, atau paket komunitas @golevelup/nestjs-rabbitmq yang menyediakan registrasi consumer berbasis dekorator yang lebih bersih.
Pilih BullMQ ketika: stack Anda hanya Node.js, Anda sudah memiliki Redis, Anda membutuhkan pekerjaan terjadwal/tertunda, Anda ingin UI dashboard disertakan, dan antrian Anda internal untuk satu kelompok layanan. Pilih RabbitMQ ketika: beberapa bahasa memproduksi atau mengonsumsi pesan, Anda membutuhkan topologi routing yang kompleks, infrastruktur messaging Anda dibagikan antar tim, atau Anda membutuhkan jaminan protokol tingkat AMQP.
Memposisikan ketiganya: BullMQ adalah antrian pekerjaan — bagus untuk tugas latar belakang, pekerjaan terjadwal, dan pola retry-with-backoff dalam ekosistem Node.js. RabbitMQ adalah message broker — bagus untuk sistem event-driven polyglot dengan persyaratan routing. Kafka adalah platform event streaming — bagus untuk replay event throughput tinggi, event sourcing, dan sistem di mana beberapa layanan membutuhkan riwayat event yang tahan lama.