Debugging Gateway AI sering terasa membingungkan karena gejalanya muncul di banyak titik sekaligus: request user melambat, gateway terlihat sibuk, provider LLM mengembalikan timeout, lalu layanan hilir mulai mengeluarkan 5xx. Dalam banyak kasus, masalah utamanya bukan satu bug tunggal, melainkan kombinasi kebijakan timeout, retry, fallback, dan observability yang tidak dirancang sebagai satu sistem end-to-end.
Artikel ini membahas studi kasus backend yang realistis pada AI gateway yang meneruskan request ke beberapa provider LLM. Fokus utamanya adalah bagaimana timeout berantai terjadi, mengapa retry justru memperburuk latensi dan beban, bagaimana fallback tanpa circuit breaker menciptakan efek domino, dan bagaimana memperbaikinya dengan timeout budget, retry idempoten, circuit breaker, correlation ID, dan guardrail fallback. Konteksnya sejalan dengan peran AI gateway sebagai lapisan kontrol untuk routing, observability, dan kebijakan akses ke model, tetapi pembahasan di sini murni dari sisi debugging dan operasi sistem.
Arsitektur singkat dan gejala yang muncul
Misalkan sebuah layanan memiliki alur seperti ini:
- Klien memanggil endpoint
/chatdi backend aplikasi. - Backend meneruskan request ke AI gateway.
- Gateway memilih provider utama, misalnya Provider A.
- Jika gagal, gateway melakukan retry atau fallback ke Provider B.
- Respons dari provider dikembalikan ke backend aplikasi lalu ke klien.
Secara sederhana terlihat aman. Namun gejala produksi menunjukkan hal berikut:
- Persentase timeout naik tajam pada jam sibuk.
- Latency p95 dan p99 melonjak, sementara throughput tidak naik signifikan.
- Gateway menampilkan banyak retry ke provider yang sama.
- Fallback ke provider kedua ikut meningkat.
- Layanan hilir mulai memunculkan error 5xx karena koneksi menumpuk atau antrean habis.
- Log sulit ditelusuri karena satu request user menghasilkan banyak log tanpa identitas bersama.
Gejala ini sering membuat tim salah fokus ke stabilitas provider LLM. Padahal provider memang bisa melambat, tetapi arsitektur retry dan timeout lokal dapat mengubah gangguan kecil menjadi insiden besar.
Studi kasus: bagaimana timeout berantai terjadi
Alur request yang tampak normal di atas kertas
Anggap konfigurasi awalnya seperti ini:
- Timeout backend aplikasi ke gateway: 10 detik.
- Gateway mencoba Provider A dengan timeout 8 detik.
- Jika gagal, gateway melakukan 2 retry ke Provider A.
- Jika tetap gagal, gateway fallback ke Provider B dengan timeout 8 detik.
- Provider B juga memiliki 1 retry internal di sisi gateway.
Masalahnya langsung terlihat: total kemungkinan waktu tunggu jauh melebihi timeout dari pemanggil di atasnya. Walaupun angka pastinya bergantung pada implementasi, pola ini hampir pasti buruk. Klien atau backend aplikasi sudah menyerah lebih dulu, sementara gateway masih sibuk mencoba request tambahan ke provider.
Apa yang terjadi saat provider utama mulai lambat
Saat Provider A melambat, request pertama mendekati timeout. Gateway lalu memicu retry. Karena retry dilakukan ketika sistem sudah lambat, retry itu tidak menyelesaikan akar masalah, malah menambah beban ke koneksi, thread worker, event loop, atau connection pool. Ketika retry ke Provider A gagal, gateway pindah ke Provider B. Jika Provider B juga menerima lonjakan fallback dari banyak request lain, provider cadangan ikut jenuh.
Efeknya berantai:
- Request awal lambat.
- Gateway menambah retry.
- Retry memperbesar antrean dan penggunaan resource.
- Fallback menggeser beban ke provider cadangan.
- Provider cadangan ikut melambat.
- Request upstream timeout lebih dulu.
- Gateway tetap melanjutkan pekerjaan yang hasilnya tidak lagi dipakai.
- Layanan hilir melihat lonjakan 5xx, timeout, atau pool exhaustion.
Ini bukan sekadar timeout biasa. Ini adalah timeout berantai yang diperparah oleh retry dan fallback yang tidak dikendalikan.
Langkah investigasi yang benar
1. Mulai dari timeline, bukan dari asumsi
Kesalahan umum saat debugging Gateway AI adalah langsung menyimpulkan “provider X sedang down”. Investigasi yang lebih tepat adalah menyusun timeline per request:
- Kapan request masuk ke backend aplikasi?
- Kapan request diteruskan ke gateway?
- Berapa lama percobaan pertama ke Provider A?
- Apakah terjadi retry? Berapa kali?
- Apakah fallback ke Provider B terjadi?
- Kapan upstream timeout?
- Apakah gateway masih memproses request setelah upstream sudah putus?
Jika sistem belum memiliki distributed tracing, minimal pastikan log dapat dihubungkan dengan correlation ID. Tanpa itu, tim akan mengandalkan timestamp kasar dan pencarian manual yang rawan salah.
2. Metrik yang perlu diperiksa
Beberapa metrik paling berguna pada kasus ini:
- Latency per hop: backend ke gateway, gateway ke Provider A, gateway ke Provider B.
- Retry rate: jumlah retry per provider dan per endpoint.
- Fallback rate: seberapa sering provider cadangan dipakai.
- Timeout count: dibagi menurut sumber, misalnya connect timeout, read timeout, upstream timeout.
- 5xx rate pada gateway dan layanan hilir.
- Concurrency dan queue depth pada worker, thread pool, atau event loop.
- Connection pool saturation jika memakai HTTP client dengan pool koneksi.
- Cancellation rate: apakah request upstream dibatalkan tetapi pekerjaan downstream tetap berjalan.
Metrik ini membantu membedakan antara masalah provider eksternal dan masalah kebijakan internal.
3. Log yang seharusnya ada
Pada setiap percobaan request ke provider, log minimal sebaiknya memuat:
correlation_idrequest_idinternal gatewayproviderattempttimeout_msduration_msresultseperti success, timeout, 429, 5xx, canceledfallback_fromjika request berpindah provider
Tanpa field tersebut, tim biasanya hanya melihat “timeout ke provider” berulang kali tanpa tahu request mana yang saling terkait.
4. Hipotesis awal yang salah tapi masuk akal
Dalam studi kasus ini, beberapa hipotesis awal ternyata keliru:
- Hipotesis 1: bug ada di provider utama. Salah sebagian. Provider utama memang melambat, tetapi lonjakan kegagalan lebih besar daripada gangguan aslinya karena gateway menambah beban lewat retry berantai.
- Hipotesis 2: fallback sudah cukup untuk high availability. Salah. Fallback tanpa pembatasan hanya memindahkan ledakan trafik ke provider cadangan.
- Hipotesis 3: memperbesar timeout akan menyelesaikan masalah. Salah. Timeout yang lebih panjang tanpa budget end-to-end justru menahan resource lebih lama dan memperburuk antrean.
- Hipotesis 4: masalah ada di jaringan. Bisa saja, tetapi bukti utama menunjukkan pola retry dan timeout yang tidak konsisten antar lapisan.
Root cause final
Setelah log dan metrik ditata ulang, akar masalah akhirnya jelas dan terdiri dari tiga bagian yang saling memperkuat:
1. Timeout upstream lebih pendek dari total retry budget
Backend aplikasi menunggu misalnya 10 detik, tetapi gateway memiliki kombinasi timeout dan retry yang secara total bisa memakan waktu lebih lama. Akibatnya, upstream menutup request lebih dulu, sementara gateway terus mencoba ke provider. Ini menghasilkan pekerjaan sia-sia, pemborosan resource, dan antrean yang terus tumbuh.
2. Fallback provider tanpa circuit breaker
Ketika Provider A melambat, semua request gagal diarahkan ke Provider B. Karena tidak ada circuit breaker atau pembatas fallback, Provider B menerima lonjakan mendadak. Jika Provider B juga mulai melambat, gateway tetap memaksakan percobaan. Hasilnya adalah kegagalan massal di dua sisi sekaligus.
3. Logging tidak punya correlation ID
Masalah sebenarnya sulit dibuktikan karena satu request user bisa memicu beberapa attempt ke beberapa provider, tetapi semua log tampak seperti kejadian terpisah. Tanpa correlation ID, tim tidak bisa melihat bahwa timeout di backend aplikasi berhubungan langsung dengan retry dan fallback yang terus berjalan di gateway.
Contoh alur request yang bermasalah
Berikut contoh alur yang umum terjadi:
- Request masuk ke backend aplikasi dengan SLA 10 detik.
- Backend memanggil gateway.
- Gateway mencoba Provider A, timeout 8 detik.
- Pada detik ke-8, Provider A belum menjawab. Gateway retry.
- Percobaan kedua juga lambat. Sementara itu backend aplikasi sudah mendekati timeout.
- Gateway memutuskan fallback ke Provider B.
- Backend aplikasi timeout di detik ke-10 dan mengembalikan error ke klien.
- Gateway masih menjalankan request ke Provider B walaupun hasilnya tidak lagi dibutuhkan.
- Ratusan request lain melakukan pola yang sama, memenuhi pool koneksi dan worker.
- Layanan hilir mulai mengembalikan 5xx atau timeout tambahan.
Di dashboard, tim melihat banyak error 5xx dan mengira sumber utama ada di hilir. Padahal 5xx tersebut sering kali merupakan gejala lanjutan dari kebijakan retry dan fallback yang salah.
Perbaikan praktis yang benar-benar bekerja
1. Terapkan timeout budget end-to-end
Prinsip utamanya: seluruh percobaan di gateway harus muat di dalam budget request dari upstream. Jangan menetapkan timeout per provider tanpa menghitung totalnya.
Contoh pendekatan:
- Jika SLA request dari backend ke gateway adalah 10 detik, sisihkan margin untuk serialisasi, antrean, dan pengiriman respons.
- Misalnya budget efektif di gateway hanya 8 detik.
- Semua retry dan fallback harus berbagi budget 8 detik itu, bukan masing-masing punya timeout penuh.
Dengan cara ini, gateway berhenti mencoba ketika budget habis. Ia tidak lagi melakukan pekerjaan yang kemungkinan besar sudah tidak berguna.
Secara implementasi, gateway perlu menghitung deadline absolut, bukan sekadar timeout relatif per attempt. Pseudocode sederhana:
deadline = now() + 8000ms
for provider in routing_plan:
while should_retry(provider):
remaining = deadline - now()
if remaining <= 0:
return timeout_error("budget exhausted")
attempt_timeout = min(provider.max_attempt_timeout, remaining)
result = call_provider(provider, timeout=attempt_timeout)
if result.success:
return result
if !is_retryable(result):
breakPendekatan ini bekerja karena keputusan retry didasarkan pada sisa waktu nyata, bukan pada konfigurasi statis yang saling bertentangan.
2. Batasi retry hanya untuk kasus yang idempoten dan benar-benar retryable
Retry bukan default untuk semua error. Untuk request ke LLM, pertimbangkan hal berikut:
- Retry lebih aman untuk timeout sementara, kegagalan jaringan sesaat, atau 429/5xx tertentu, tergantung kontrak API provider.
- Hindari retry membabi buta untuk error validasi, permintaan buruk, atau respons yang menunjukkan kegagalan permanen.
- Pastikan operasi idempoten dari sisi gateway. Jika request bisa menyebabkan efek samping seperti pencatatan biaya, penyimpanan hasil, atau audit event, desain idempotency key dengan benar.
Tambahkan juga backoff dan sedikit jitter agar retry dari banyak worker tidak terjadi serempak.
{
"retry": {
"max_attempts": 2,
"retry_on": ["timeout", "connect_error", "429", "5xx"],
"backoff": "exponential",
"jitter": true
}
}Contoh di atas hanya ilustrasi konfigurasi, tetapi idenya jelas: retry dibatasi, selektif, dan tidak berjalan tanpa kontrol.
3. Tambahkan circuit breaker pada fallback provider
Fallback memang berguna, tetapi harus dilindungi circuit breaker. Jika provider utama sedang buruk, gateway tidak boleh langsung mengalihkan semua trafik ke provider cadangan tanpa melihat kesehatan provider cadangan tersebut.
Circuit breaker membantu dalam tiga kondisi:
- Open: hentikan request baru ke provider yang jelas-jelas sedang gagal berat.
- Half-open: kirim sebagian kecil request sebagai uji pemulihan.
- Closed: lanjutkan operasi normal jika provider sehat kembali.
Untuk fallback, tambahkan guardrail tambahan:
- Batas maksimum persentase trafik yang boleh dialihkan ke provider cadangan.
- Batas concurrency per provider.
- Kebijakan fail-fast jika provider cadangan juga menunjukkan tanda jenuh.
Ini penting karena fallback tanpa guardrail sering berubah menjadi load amplifier.
4. Hentikan pekerjaan downstream saat upstream sudah batal
Jika backend aplikasi atau klien sudah timeout atau membatalkan request, gateway sebaiknya membatalkan panggilan ke provider sejauh implementasi dan kontrak jaringan memungkinkan. Tanpa propagasi pembatalan, gateway akan terus menghabiskan koneksi dan CPU untuk hasil yang tidak akan pernah dikirim ke siapa pun.
Prinsip ini sering dilupakan. Tim merasa timeout upstream adalah akhir masalah, padahal resource di bawahnya masih terpakai sampai attempt selesai.
5. Perbaiki observability: correlation ID, tracing, dan log terstruktur
Perbaikan teknis sulit divalidasi tanpa observability yang memadai. Minimal lakukan ini:
- Tambahkan
X-Correlation-IDatau field setara dari ingress sampai provider call. - Gunakan log terstruktur JSON, bukan string bebas.
- Catat event penting: request diterima, provider dipilih, retry, fallback, timeout, cancellation, response final.
- Jika memungkinkan, gunakan trace/span untuk tiap hop.
Contoh log terstruktur:
{
"timestamp": "2026-07-05T10:15:02Z",
"correlation_id": "c-8f31",
"gateway_request_id": "g-10291",
"provider": "provider-a",
"attempt": 2,
"timeout_ms": 2500,
"duration_ms": 2498,
"result": "timeout",
"fallback_from": null
}Saat fallback terjadi:
{
"timestamp": "2026-07-05T10:15:05Z",
"correlation_id": "c-8f31",
"gateway_request_id": "g-10291",
"provider": "provider-b",
"attempt": 1,
"timeout_ms": 1800,
"duration_ms": 1100,
"result": "success",
"fallback_from": "provider-a"
}Dengan format seperti ini, satu incident bisa ditelusuri per request, bukan hanya per server.
6. Terapkan guardrail fallback yang eksplisit
Fallback sebaiknya bukan “jika gagal, kirim ke semua alternatif”. Tetapkan aturan seperti:
- Fallback hanya untuk jenis error tertentu.
- Fallback hanya jika sisa timeout budget masih cukup.
- Fallback hanya jika circuit breaker provider cadangan tidak open.
- Fallback dibatasi oleh kuota concurrency dan rate limit internal.
- Fallback dimatikan sementara jika kualitas respons provider cadangan tidak sesuai kebutuhan endpoint tertentu.
Ini mencegah fallback menjadi mekanisme panik yang justru memperbesar radius kerusakan.
Contoh kebijakan routing yang lebih aman
Berikut contoh pendekatan kebijakan yang lebih waras untuk endpoint sinkron:
- Total deadline dari gateway: 8 detik.
- Provider utama mendapat 1 attempt awal.
- Retry maksimal 1 kali hanya untuk timeout singkat atau connect error.
- Fallback hanya jika sisa budget masih cukup, misalnya minimal 2 detik.
- Provider cadangan tidak boleh menerima lebih dari batas concurrency tertentu.
- Jika kedua provider dalam kondisi buruk, fail fast dengan error terkontrol daripada menunggu hingga semua resource habis.
Pola ini mungkin sedikit menurunkan peluang “berhasil bagaimanapun caranya”, tetapi jauh lebih baik untuk stabilitas sistem secara keseluruhan.
Trade-off dan hal yang sering disalahpahami
Timeout lebih besar tidak selalu lebih baik
Timeout panjang bisa membantu request yang memang butuh waktu, tetapi pada sistem dengan trafik tinggi, timeout panjang juga menahan worker dan koneksi lebih lama. Jika tidak dihitung sebagai budget end-to-end, timeout panjang memperbesar antrean dan memperlambat semua request lain.
Retry meningkatkan availability, tetapi juga bisa memperburuk overload
Retry berguna untuk gangguan transien. Namun saat penyebab utamanya adalah saturasi atau latensi tinggi yang sudah berlangsung, retry menambah tekanan pada komponen yang sedang kewalahan. Karena itu retry harus konservatif dan terukur.
Fallback tidak sama dengan high availability
Memiliki dua provider tidak otomatis membuat sistem tahan gagal. Tanpa circuit breaker, kuota, dan pembatas concurrency, fallback justru menyebarkan kegagalan ke lebih banyak komponen.
Observability bukan fitur tambahan
Pada arsitektur multi-provider, observability adalah bagian dari desain inti. Tanpa correlation ID dan trace yang konsisten, root cause analysis akan lambat dan sering berujung pada kesimpulan yang salah.
Checklist debugging untuk insiden berikutnya
- Periksa apakah timeout upstream lebih kecil daripada akumulasi retry dan fallback di gateway.
- Ukur retry rate dan fallback rate per provider.
- Lihat apakah request tetap berjalan setelah upstream canceled.
- Periksa saturasi worker, queue, dan connection pool.
- Telusuri satu request end-to-end menggunakan correlation ID.
- Pastikan fallback hanya terjadi untuk error yang memang layak dialihkan.
- Periksa status circuit breaker dan batas concurrency per provider.
- Bandingkan p95/p99 latency sebelum dan sesudah retry/fallback meningkat.
Penutup
Kasus timeout berantai pada AI gateway jarang disebabkan oleh satu komponen saja. Yang lebih sering terjadi adalah kombinasi dari timeout upstream yang terlalu pendek dibanding total retry budget, fallback provider tanpa circuit breaker, dan observability yang lemah karena tidak ada correlation ID. Begitu provider utama melambat, gateway mulai memperbanyak percobaan, memindahkan beban ke provider cadangan, lalu memicu efek domino sampai layanan hilir mengembalikan 5xx.
Perbaikan yang efektif bukan sekadar memperbesar timeout atau menambah provider. Solusi yang benar adalah merancang timeout budget end-to-end, membatasi retry hanya untuk kasus idempoten dan retryable, melindungi fallback dengan circuit breaker dan guardrail, serta memastikan setiap request bisa ditelusuri dengan correlation ID dan tracing. Dengan fondasi ini, AI gateway benar-benar berfungsi sebagai lapisan kontrol, bukan sumber amplifikasi kegagalan.
Catatan praktis: jika Anda mengelola gateway ke beberapa provider LLM, mulai audit dari tiga hal ini hari ini juga: deadline end-to-end, kebijakan retry, dan log dengan correlation ID. Tiga titik ini paling sering menjadi pembeda antara gangguan kecil dan insiden besar.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!