Poison Message Handling #
Dalam sistem asynchronous berbasis RabbitMQ, sebagian besar kegagalan bersifat sementara.
Namun ada jenis kegagalan yang lebih berbahaya:
Pesan yang akan selalu gagal, tidak peduli berapa kali dicoba.
Inilah yang disebut Poison Message.
Jika tidak ditangani dengan benar, poison message dapat:
- Menyebabkan infinite retry loop
- Menghambat throughput
- Mengganggu ordering
- Menghabiskan resource
- Bahkan melumpuhkan sistem
Artikel ini membahas bagaimana mengenali dan menangani poison message secara arsitektural dalam RabbitMQ.
“Tidak semua pesan gagal karena sistem belum siap — sebagian gagal karena memang tidak bisa diperbaiki.”
Apa Itu Poison Message? #
Poison message adalah message yang:
- Selalu gagal diproses oleh consumer
- Tidak akan pernah sukses meskipun dicoba ulang
Contoh kasus:
- Payload tidak sesuai schema
- Data corrupt
- Business rule tidak terpenuhi
- Referensi data tidak pernah ada
Retry terhadap pesan seperti ini tidak akan membantu.
Ia hanya memperparah masalah.
Bagaimana Poison Message Terjadi? #
Beberapa penyebab umum:
1️⃣ Perubahan Schema Tanpa Backward Compatibility #
Producer mengirim versi baru. Consumer lama tidak bisa memproses.
2️⃣ Data Invalid Permanen #
Contoh:
- Email kosong
- ID negatif
- Field wajib hilang
3️⃣ Bug Logic Bisnis #
Consumer selalu melempar exception untuk tipe data tertentu.
4️⃣ Dependency Tidak Pernah Valid #
Contoh:
- Order referensi ke produk yang sudah dihapus permanen
Dampak Jika Tidak Ditangani #
Jika poison message terus di-requeue:
- Consumer terus memproses pesan yang sama
- Message lain tertahan
- Throughput turun drastis
- CPU spike
- Queue tidak pernah bersih
Ini disebut poison message loop.
Dalam skenario ekstrem, sistem bisa terlihat hidup tetapi tidak memproses pekerjaan nyata.
Strategi Penanganan Poison Message #
Penanganan yang matang biasanya terdiri dari beberapa lapisan.
1️⃣ Batasi Jumlah Retry #
Gunakan header seperti:
x-retry-count
Setiap kali message gagal:
- Tambah retry-count
- Jika melebihi batas (misal 5 kali) → jangan requeue lagi
Batas retry adalah garis pertahanan pertama.
2️⃣ Gunakan Dead Letter Exchange (DLX) #
Jika retry-count melebihi batas:
- Nack dengan
requeue=false - Message masuk ke DLQ permanen
DLQ menjadi tempat isolasi poison message.
3️⃣ Pisahkan Retry Queue dan Final DLQ #
Arsitektur umum:
Main Queue
|
v
Retry Queue (TTL + backoff)
|
v
Main Exchange
Jika melebihi batas:
|
v
Final DLQ
Retry queue untuk error sementara. Final DLQ untuk poison message permanen.
4️⃣ Logging dan Observability #
Poison message tidak boleh diam.
Setiap pesan yang masuk DLQ harus:
- Dilog
- Diberi context error
- Dipantau metric-nya
DLQ depth yang meningkat adalah sinyal ada bug.
5️⃣ Reprocessing Manual atau Terprogram #
DLQ bukan kuburan.
Ia bisa digunakan untuk:
- Investigasi manual
- Reprocessing setelah bug diperbaiki
- Export untuk analisis
Namun reprocessing harus disengaja dan terkendali.
Poison Message vs Transient Failure #
| Aspek | Transient Error | Poison Message |
|---|---|---|
| Retry membantu | Ya | Tidak |
| Cocok untuk backoff | Ya | Tidak |
| Perlu DLQ permanen | Kadang | Ya |
| Dampak jika di-requeue terus | Retry storm | Infinite loop |
Membedakan keduanya adalah tanggung jawab consumer logic.
Deteksi Dini Poison Message #
Beberapa teknik:
- Validasi schema di awal
- Gunakan versioned event
- Gunakan circuit breaker untuk dependency
- Pisahkan error validation dan error transient
Semakin cepat dideteksi, semakin kecil dampaknya.
Poison Message dalam Quorum Queue #
Pada quorum queue:
- Poison message tetap direplikasi
- Tetap konsisten
- Tetap bisa menyebabkan retry loop
Quorum queue tidak menyelesaikan poison message.
Masalahnya ada di level aplikasi.
Risiko Jika Tidak Ada Strategi #
Tanpa poison message handling:
- Retry tanpa batas
- Queue starvation
- Message lain tertahan
- SLA gagal
- Sistem terlihat hidup tetapi tidak produktif
Ini salah satu kegagalan paling berbahaya dalam sistem asynchronous.
Best Practice Production #
- Selalu batasi retry
- Pisahkan retry sementara dan DLQ permanen
- Monitor DLQ depth
- Tambahkan retry-count header
- Bedakan error transient vs permanen
- Audit message schema evolution
Poison message harus dianggap bagian dari desain, bukan kejutan.
Ringkasan #
| Konsep | Penjelasan |
|---|---|
| Poison message | Message yang selalu gagal |
| Risiko utama | Infinite retry loop |
| Solusi | Retry limit + DLQ |
| Observability | Wajib |
| Root cause | Biasanya schema / logic mismatch |
Penutup #
Poison message bukan sekadar pesan gagal.
Ia adalah indikator bahwa ada ketidaksesuaian antara kontrak dan implementasi.
Sistem yang matang tidak hanya mampu retry.
Ia mampu mengenali kapan harus berhenti mencoba.
Dalam arsitektur RabbitMQ production, kemampuan mengisolasi poison message sering kali menjadi pembeda antara sistem yang stabil dan sistem yang perlahan runtuh di bawah beban kesalahan yang tak pernah selesai.
Karena tidak semua kegagalan harus dilawan — sebagian harus diisolasi.