Retry Logic Gak Selalu Bikin Sistem Lebih Andal
Retry sering kelihatan seperti obat universal untuk request gagal. Padahal kalau dipasang tanpa batas, dia bisa berubah dari mekanisme penyelamat jadi amplifier masalah.
0xNN · · 8 min read
Ada fase di hidup backend engineer ketika setiap error sementara terasa punya solusi yang sama: retry aja. Timeout? Retry. 502? Retry. Koneksi putus? Retry. Dan jujur, kadang itu memang nolong. Tapi masalahnya, retry juga salah satu cara tercepat buat bikin dependency yang lagi sakit jadi tambah ambruk.
Gue pernah lihat service internal yang sebenarnya cuma mulai lambat karena database di belakangnya kepenuhan koneksi. Harusnya cukup diredam. Yang terjadi malah kebalik: semua caller retry 3 kali, paralel, tanpa backoff yang waras. Dalam hitungan detik, service yang tadinya sakit ringan berubah jadi penuh antrean dan akhirnya tumbang. Masalah awalnya kecil. Amplifier-nya retry.
---
Retry itu berguna, tapi bukan gratis
Retry berguna kalau kegagalannya benar-benar sementara: packet loss, network hiccup, pod restart sebentar, atau rate limit yang jelas minta coba lagi nanti. Tapi retry punya biaya:
• nambah load ke dependency
• nambah latency ke user
• nambah antrean di worker atau thread pool
• nambah kemungkinan side effect dobel kalau request gak idempotent
Jadi pertanyaan yang benar bukan "apakah error ini boleh di-retry?" Tapi: siapa yang menanggung biaya retry ini? Kalau dependency yang lagi megap-megap dipaksa nerima gelombang retry, lo cuma memindahkan masalah.
---
Retry storm itu nyata
Pola retry storm biasanya gini:
1. service B melambat
2. service A timeout ke B
3. A retry 3 kali
4. 1000 request user masuk ke A
5. beban ke B naik 3-4x justru saat B paling lemah
Kalau beberapa layer melakukan ini sekaligus, efeknya gila. API gateway retry, app retry, SDK retry, worker retry. Satu request user bisa beranak-pinak jadi sekumpulan request yang semuanya ikut panik.
Makanya gue makin suka prinsip sederhana: retry harus sadar konteks, bukan refleks.
---
Tiga hal yang wajib ada
1. Exponential backoff
Jangan retry dengan jeda tetap 100ms, 100ms, 100ms. Itu terlalu agresif. Delay harus makin panjang supaya dependency punya ruang bernapas.
2. Jitter
Kalau semua client retry di detik yang sama, lo bikin lonjakan serempak. Tambahin randomization supaya retry menyebar. Ini salah satu trik paling murah tapi paling penting.
3. Retry budget
Batasin total retry. Jangan biarkan satu request hidup terlalu lama sambil bikin antrean makin tebal. Ada titik di mana gagal cepat lebih sehat daripada optimisme palsu.
for (let attempt = 1; attempt <= 3; attempt++) {
try {
return await callService()
} catch (err) {
if (!isRetryable(err) || attempt === 3) throw err
const backoff = Math.min(1000, 100 * 2 attempt)
const jitter = Math.floor(Math.random() * 100)
await sleep(backoff + jitter)
}
}
---
Kapan jangan retry
Ada beberapa kondisi di mana retry justru ide jelek:
• request gak idempotent
• error jelas permanent, misalnya 400 validation error
• dependency lagi overload dan lo gak punya circuit breaker
• user request sifatnya interactive dan retry akan nambah UX delay parah
Kadang yang lebih waras adalah kasih error yang jujur, log yang rapi, dan mekanisme compensating action di belakang. Tidak semua kegagalan harus ditutup pakai retry.
---
Retry bukan pengganti design
Banyak tim pakai retry buat nutupin akar masalah lain: timeout terlalu pendek, pool connection bocor, query lambat, atau service dependency yang kontraknya gak jelas. Retry bisa jadi plester, tapi jangan diperlakukan seperti fondasi.
Kalau lo butuh retry di hampir semua endpoint karena semuanya sering gagal sementara, biasanya ada problem yang lebih dalam di arsitektur atau operasional.
---
Referensi yang layak dibaca
• AWS Builders' Library - Timeouts, retries, and backoff with jitter
• Google SRE Book
• Stripe Engineering Blog
• Designing Data-Intensive Applications
---
Gue gak anti retry. Gue cuma makin alergi sama retry yang dipasang otomatis tanpa mikir. Retry itu alat yang bagus kalau lo ngerti kapan dipakai, berapa kali, dan siapa yang bakal ngebayar biayanya.
Kalau sekarang lo lagi lihat sistem yang suka timeout dan insting pertama lo adalah "tambah retry", berhenti sebentar. Mungkin itu solusi. Mungkin juga itu cara tercepat bikin dependency yang udah batuk berubah jadi ICU.
---
*ditulis setelah ngeliat service yang harusnya cuma batuk sebentar malah tumbang total gara-gara semua caller kompak optimis dan retry bareng-bareng.*