Retry Pattern #
Dalam sistem asynchronous berbasis RabbitMQ, kegagalan adalah hal yang normal.
Namun sistem yang matang tidak hanya mampu mendeteksi kegagalan. Ia harus memiliki strategi retry yang terstruktur.
Retry tanpa desain yang jelas dapat menyebabkan:
- Infinite retry loop
- Retry storm
- CPU spike
- Dependency overload
- Queue starvation
Artikel ini membahas berbagai retry pattern dalam RabbitMQ, dari yang sederhana hingga production-grade, lengkap dengan tradeoff dan best practice.
“Retry bukan tentang mencoba lagi secepat mungkin — tetapi tentang mencoba lagi pada waktu yang tepat, dengan batas yang jelas.”
Mengapa Retry Pattern Dibutuhkan? #
Sebagian besar kegagalan dalam sistem terdistribusi bersifat transient:
- Database timeout
- Network glitch
- Service dependency overload
- Lock contention
Jika tidak dilakukan retry:
- Message langsung gagal
- Data bisa hilang
Namun jika retry dilakukan tanpa kontrol:
- Sistem bisa runtuh karena terlalu agresif mencoba ulang
Retry pattern adalah kompromi antara ketahanan dan stabilitas.
Retry Langsung (Immediate Requeue) #
Pendekatan paling sederhana:
Consumer melakukan:
basic.nack(requeue = true)
Message langsung kembali ke queue utama.
Kelebihan #
- Implementasi sangat sederhana
- Tidak perlu queue tambahan
Kekurangan #
- Tidak ada delay
- Berisiko infinite loop
- Tidak membedakan transient vs permanent error
- Tidak cocok untuk production
Immediate requeue jarang direkomendasikan untuk sistem serius.
Retry dengan TTL + Dead Letter Exchange (Dasar) #
Pendekatan yang lebih sehat menggunakan:
- Dead Letter Exchange (DLX)
- Retry queue
- TTL
1. Diagram Retry Dasar #
Main Queue
|
| gagal (nack requeue=false)
v
Retry Queue (TTL 10 detik)
|
v
Main Exchange
Alur:
- Message gagal
- Nack dengan requeue=false
- Masuk ke retry queue
- TTL habis
- Message kembali ke exchange utama
- Diproses ulang
Pendekatan ini memberi delay sebelum retry.
Retry dengan Exponential Backoff #
Alih-alih delay tetap, kita bisa meningkatkan delay setiap percobaan.
Contoh pola:
- Retry 1 → 1 detik
- Retry 2 → 2 detik
- Retry 3 → 4 detik
- Retry 4 → 8 detik
Implementasi dapat dilakukan dengan:
1️⃣ Multiple Retry Queue Berjenjang #
Retry-1 (TTL 1s)
Retry-2 (TTL 2s)
Retry-3 (TTL 4s)
Retry-4 (TTL 8s)
Setiap kegagalan dipindahkan ke queue berikutnya.
2️⃣ Single Retry Queue + Dynamic TTL #
- Simpan
x-retry-countdi header - Hitung delay di aplikasi
- Publish ulang dengan TTL baru
Pendekatan kedua lebih fleksibel dan scalable.
Retry Counter: Komponen Wajib #
Setiap retry pattern harus memiliki batas.
Tambahkan header:
x-retry-count
Alur umum:
- Message gagal
- Tambah retry-count
- Jika retry-count < max → kirim ke retry queue
- Jika retry-count ≥ max → kirim ke DLQ permanen
Tanpa retry counter, retry bisa tak terbatas.
Retry dengan Delayed Exchange Plugin #
RabbitMQ memiliki plugin bernama:
rabbitmq_delayed_message_exchange
Dengan plugin ini:
- Kita bisa menentukan delay langsung saat publish
- Tidak perlu queue TTL terpisah
Contoh konsep:
x-delay = 5000
Plugin ini menyederhanakan arsitektur retry.
Namun:
- Tidak selalu tersedia di semua environment
- Perlu instalasi tambahan
Perbandingan Retry Pattern #
| Pattern | Kompleksitas | Stabilitas | Cocok untuk |
|---|---|---|---|
| Immediate Requeue | Rendah | Rendah | Demo / test |
| TTL + DLX (Fixed Delay) | Sedang | Baik | Transient ringan |
| Exponential Backoff | Tinggi | Sangat baik | Dependency outage |
| Delayed Exchange Plugin | Sedang | Baik | Arsitektur modern |
Untuk production-grade system, exponential backoff + retry limit adalah standar.
Retry dan Ordering #
Retry dapat memengaruhi ordering.
Message yang gagal akan diproses lebih lambat dibanding message berikutnya.
Jika ordering sangat penting:
- Gunakan partitioned queue berdasarkan key
- Atau desain consumer agar idempotent dan tolerant terhadap out-of-order
Retry dan strict ordering jarang bisa dipertahankan bersamaan.
Retry dan Quorum Queue #
Pada quorum queue:
- Retry tetap menggunakan DLX + TTL
- Replikasi tetap konsisten
- Duplicate tetap mungkin terjadi
Retry logic tetap berada di level aplikasi.
Kesalahan Umum dalam Retry Pattern #
- Tidak membedakan error transient dan permanen
- Retry tanpa batas
- Tidak memiliki DLQ final
- Tidak memonitor retry rate
- Tidak menggunakan jitter pada backoff
Retry yang buruk lebih berbahaya daripada tidak retry sama sekali.
Best Practice Production #
- Gunakan exponential backoff
- Tambahkan jitter kecil untuk menghindari thundering herd
- Batasi retry count
- Pisahkan retry queue dan DLQ permanen
- Monitor retry rate dan DLQ depth
- Dokumentasikan retry policy sebagai bagian kontrak sistem
Retry adalah bagian dari reliability architecture, bukan sekadar fitur tambahan.
Ringkasan #
| Komponen | Peran |
|---|---|
| Retry queue | Menunda percobaan ulang |
| TTL | Mengatur delay |
| DLX | Mengalihkan pesan gagal |
| Retry counter | Membatasi percobaan |
| Backoff | Mengurangi retry storm |
Penutup #
Retry pattern adalah salah satu fondasi penting dalam sistem messaging modern.
Ia menentukan apakah sistem akan:
- Pulih dengan elegan
- Atau menghancurkan dirinya sendiri karena terlalu agresif mencoba lagi
Dalam RabbitMQ, retry bukan fitur bawaan yang otomatis aman.
Ia harus dirancang secara sadar dengan mempertimbangkan:
- Stabilitas dependency
- Ordering
- Duplicate handling
- Observability
Karena dalam sistem asynchronous, ketahanan bukan hanya soal bisa mencoba lagi.
Tetapi soal tahu kapan harus mencoba, seberapa lama menunggu, dan kapan harus berhenti.