Integrasi API pihak ketiga yang aman: retry, timeout, pemutus sirkuit
Integrasi aman dengan API pihak ketiga agar aplikasi tetap berjalan saat outage. Pelajari timeout, retry, circuit breaker, dan pengecekan cepat.

Mengapa API pihak ketiga bisa membuat alur kerja inti macet
API pihak ketiga bisa gagal dengan cara yang tidak terlihat seperti kejadian "mati" yang jelas. Masalah paling umum adalah melambat: permintaan menggantung, respons datang terlambat, dan aplikasi Anda terus menunggu. Jika panggilan tersebut berada di jalur kritis, gangguan kecil di luar kendali Anda menumpuk di dalam sistem.
Begitulah perlambatan lokal menjadi outage penuh. Thread atau worker terjebak menunggu, antrean membesar, transaksi database tetap terbuka lebih lama, dan permintaan baru mulai mengalami timeout. Tak lama kemudian, bahkan halaman yang tidak menggunakan API eksternal terasa rusak karena sistem kewalahan oleh pekerjaan yang menunggu.
Dampaknya nyata. Penyedia identitas yang tidak stabil memblokir pendaftaran dan login. Timeout gateway pembayaran membekukan proses checkout, membuat pengguna bingung apakah mereka sudah dibebankan. Penundaan pesan menghentikan reset kata sandi dan konfirmasi pesanan, yang memicu gelombang retry dan tiket dukungan.
Tujuannya sederhana: isolasi kegagalan eksternal agar alur kerja inti tetap berjalan. Itu bisa berarti membiarkan pengguna membuat pesanan lalu mengonfirmasi pembayaran kemudian, atau mengizinkan pendaftaran meski email sambutan gagal.
Metrik keberhasilan praktis: ketika penyedia lambat atau down, aplikasi Anda tetap merespons cepat dan jelas, serta radius dampak tetap kecil. Misalnya, sebagian besar permintaan inti masih selesai dalam anggaran latensi normal, kegagalan tetap terbatas pada fitur yang bergantung pada API tersebut, pengguna melihat status yang jelas (queued, pending, coba lagi nanti), dan pemulihan terjadi otomatis saat penyedia kembali.
Mode kegagalan yang harus Anda rencanakan
Sebagian besar kegagalan dapat diprediksi, meskipun waktunya tidak. Sebutkan di depan dan Anda bisa memutuskan apa yang harus di-retry, apa yang harus dihentikan, dan apa yang ditampilkan ke pengguna.
Kategori umum:
- Lonjakan latensi (permintaan tiba-tiba 10x lebih lama)
- Kesalahan server atau jaringan sementara (timeout, 502/503, reset koneksi)
- Batasan laju dan habis kuota (429, batas harian)
- Masalah otentikasi dan izin (kunci kadaluarsa, akses dicabut)
- Data buruk atau mengejutkan (field hilang, format salah, respons parsial)
Tidak semua error berarti hal yang sama. Masalah sementara sering layak di-retry karena panggilan berikutnya mungkin berhasil (gangguan jaringan, timeout, 502/503, dan beberapa 429 setelah menunggu). Masalah permanen biasanya tidak akan memperbaiki dirinya sendiri (kredensial tidak valid, endpoint salah, request yang salah format, penolakan izin).
Memperlakukan semua error sama bisa mengubah insiden kecil menjadi downtime. Mengulang kegagalan permanen membuang-buang waktu, mempercepat pemakaian kuota, dan membangun antrean yang memperlambat semuanya. Tidak pernah mencoba ulang pada kegagalan sementara memaksa pengguna mengulang tindakan dan kehilangan pekerjaan yang seharusnya selesai beberapa saat kemudian.
Perhatikan ekstra alur kerja di mana jeda terasa seperti kegagalan: checkout, login, reset kata sandi, dan notifikasi (email/SMS/push). Lonjakan dua detik pada API marketing mengganggu. Lonjakan dua detik pada otorisasi pembayaran memblokir pendapatan.
Tes yang berguna: "Apakah panggilan ini harus selesai untuk menyelesaikan tugas utama pengguna saat ini?" Jika ya, Anda perlu timeout ketat, retry hati-hati, dan jalur kegagalan yang jelas. Jika tidak, pindahkan ke antrean dan jaga aplikasi tetap responsif.
Timeouts: pilih batas dan patuhi
Timeout adalah waktu maksimum Anda bersedia menunggu sebelum berhenti dan melanjutkan. Tanpa batas yang jelas, satu penyedia lambat bisa menumpuk permintaan yang menunggu dan memblokir pekerjaan penting.
Ada dua jenis tunggu yang membantu dipisahkan:
- Connect timeout: berapa lama Anda mencoba membuat koneksi.
- Read timeout: berapa lama Anda menunggu respons setelah terkoneksi.
Memilih angka bukan soal kesempurnaan. Ini soal mencocokkan kesabaran manusia dan alur kerja Anda.
- Jika pengguna menatap spinner, biasanya Anda butuh jawaban cepat dan langkah berikut yang jelas.
- Jika itu pekerjaan latar (misalnya sinkronisasi faktur semalaman), Anda bisa memberi lebih banyak waktu, tapi tetap butuh batas agar tidak menggantung selamanya.
Cara praktis memilih timeout adalah mundur dari pengalaman:
- Berapa lama pengguna bisa menunggu sebelum Anda perlu menampilkan pesan yang jelas?
- Jika panggilan ini gagal sekarang, bisakah Anda mencoba lagi nanti atau menggunakan fallback?
- Berapa banyak panggilan ini berjalan pada beban puncak?
Tradeoff nyata: terlalu lama dan Anda mengikat thread, worker, dan koneksi database. Terlalu singkat dan Anda menciptakan false failure dan memicu retry yang tidak perlu.
Retry yang tidak membuat outage makin parah
Retry berguna ketika kegagalan kemungkinan bersifat sementara: gangguan jaringan singkat, DNS hiccup, atau 500/502/503 satu kali. Dalam kasus tersebut, coba lagi kedua bisa berhasil dan pengguna tak menyadari apapun.
Risikonya adalah retry storm. Ketika banyak klien gagal bersamaan dan semuanya retry sekaligus, mereka dapat membebani penyedia (dan worker Anda sendiri). Backoff dan jitter mencegah itu.
Anggaran retry menjaga Anda tetap masuk akal. Batasi percobaan dan batasi total waktu agar alur kerja inti tidak terjebak menunggu pihak lain.
Resep default retry yang aman
- Retry hanya beberapa kali (seringnya 1-3 percobaan total, tergantung alur).
- Gunakan exponential backoff (misalnya 200ms, 500ms, 1s) ditambah jitter acak.
- Batasi total waktu yang dihabiskan untuk retry (sering beberapa detik pada alur yang menunggu pengguna).
- Gunakan timeout per percobaan, bukan satu timeout panjang untuk semua percobaan.
Jangan retry error klien yang dapat diprediksi seperti 400/422 masalah validasi, 401/403 masalah otentikasi, atau 404. Itu hampir pasti akan gagal lagi dan hanya menambah beban.
Satu pengaman lagi: hanya retry operasi tulis (POST/PUT) ketika Anda memiliki idempotensi, jika tidak Anda berisiko double-charge atau duplikasi data.
Idempotensi: buat retry aman untuk alur nyata
Idempotensi berarti Anda bisa menjalankan permintaan yang sama dua kali dan berakhir dengan hasil final yang sama. Itu penting karena retry adalah hal biasa: jaringan drop, server restart, dan klien timeout. Tanpa idempotensi, retry yang "membantu" menghasilkan duplikasi dan masalah uang nyata.
Bayangkan checkout: API pembayaran lambat, aplikasi Anda timeout, dan Anda retry. Jika panggilan pertama sebenarnya berhasil, retry bisa menyebabkan tagihan ganda. Risiko yang sama ada pada tindakan seperti membuat pesanan, memulai langganan, mengirim email/SMS, mengeluarkan pengembalian dana, atau membuat tiket dukungan.
Perbaikannya adalah menempelkan kunci idempotensi (atau request ID) ke setiap panggilan "melakukan sesuatu". Kunci itu harus unik per aksi pengguna, bukan per percobaan. Penyedia (atau layanan Anda sendiri) menggunakan kunci itu untuk mendeteksi duplikat dan mengembalikan hasil yang sama alih-alih melakukan aksi lagi.
Perlakukan kunci idempotensi seperti bagian dari model data, bukan header yang Anda harap tidak ada yang lupa.
Pola yang tahan di produksi
Buat satu kunci saat pengguna memulai aksi (misalnya saat mereka klik Pay), lalu simpan bersama catatan lokal Anda.
Pada setiap percobaan:
- Kirim kunci yang sama.
- Simpan hasil akhir yang Anda terima (respons sukses, kode kegagalan, ID charge).
- Jika Anda sudah punya outcome tercatat, kembalikan hasil itu alih-alih mengulangi aksi.
Jika Anda adalah "penyedia" untuk panggilan internal, tegakkan perilaku yang sama di sisi server.
Circuit breaker: hentikan panggilan saat API gagal
Circuit breaker adalah sakelar pengaman. Ketika layanan eksternal mulai gagal, Anda berhenti memanggilnya untuk periode singkat daripada menumpuk permintaan yang kemungkinan besar akan timeout.
Circuit breaker biasanya punya tiga status:
- Closed: permintaan berjalan normal.
- Open: panggilan diblokir selama jendela cooldown.
- Half-open: setelah cooldown, sejumlah kecil panggilan uji memeriksa apakah layanan pulih.
Saat breaker terbuka, aplikasi Anda harus melakukan sesuatu yang dapat diprediksi. Jika API validasi alamat down saat pendaftaran, terima alamat dan tandai untuk ditinjau nanti. Jika pemeriksaan risiko pembayaran down, antre pesanan untuk tinjauan manual atau nonaktifkan opsi itu sementara dan jelaskan alasan.
Pilih ambang yang sesuai dampak pengguna:
- kesalahan berturut-turut (misalnya 5 kegagalan berturut-turut)
- tingkat kegagalan tinggi selama jendela singkat
- banyak respons lambat (timeout)
- kode status spesifik (seperti 503 berulang)
Jaga cooldown singkat (detik sampai menit) dan batasi probe half-open. Tujuannya melindungi alur kerja inti dulu, lalu pulih cepat.
Fallback dan antrean: jaga aplikasi tetap bisa dipakai
Saat API eksternal lambat atau down, tujuan Anda adalah membuat pengguna tetap bergerak. Itu berarti punya Plan B yang jujur tentang apa yang terjadi.
Fallback: pilih pengalaman "cukup baik"
Fallback adalah apa yang dilakukan aplikasi ketika API tidak merespons tepat waktu. Opsi termasuk menggunakan data cache, beralih ke mode terdegradasi (sembunyikan widget tidak penting, nonaktifkan aksi opsional), meminta input pengguna alih-alih memanggil API (masukan alamat manual), atau menampilkan pesan jelas dengan langkah selanjutnya.
Jujur: jangan bilang sesuatu selesai jika tidak.
Antrean: lakukan nanti ketika "sekarang" tidak wajib
Jika pekerjaan tidak harus selesai dalam permintaan pengguna, dorong ke antrean dan respons cepat. Kandidat umum: mengirim email, sinkron ke CRM, menghasilkan laporan, dan posting event analytics.
Gagal cepat untuk aksi inti. Jika API tidak diperlukan untuk menyelesaikan checkout (atau pembuatan akun), jangan blokir permintaan. Terima pesanan, antre panggilan eksternal, dan rekonsiliasi nanti. Jika API diperlukan (misalnya otorisasi pembayaran), gagal cepat dengan pesan yang jelas dan jangan membuat pengguna menunggu.
Apa yang dilihat pengguna harus mencerminkan apa yang terjadi di belakang layar: status jelas (completed, pending, failed), janji yang bisa ditepati (struk sekarang, konfirmasi nanti), cara untuk mencoba ulang, dan catatan yang terlihat di UI (log aktivitas, badge pending).
Batas laju dan beban: hindari kegagalan buatan sendiri
Rate limit adalah cara penyedia mengatakan, "Anda boleh memanggil kami, tapi tidak terlalu sering." Anda akan menemukannya lebih cepat daripada perkiraan: lonjakan lalu lintas, job latar yang berjalan bersamaan, atau bug yang melakukan loop saat error.
Mulailah dengan mengontrol berapa banyak permintaan yang Anda buat. Gabungkan batch bila mungkin, cache respons bahkan selama 30–60 detik bila aman, dan throttle di sisi klien agar aplikasi Anda tidak meledak lebih cepat dari yang penyedia izinkan.
Saat Anda mendapat 429 Too Many Requests, perlakukan itu sebagai sinyal untuk memperlambat.
- Hormati header
Retry-Afterketika disediakan. - Tambahkan jitter agar banyak worker tidak retry bersamaan.
- Batasi retry untuk 429 agar tidak loop tak berujung.
- Backoff lebih agresif pada 429 berulang.
- Rekam sebagai metrik agar Anda menyadari pola sebelum pengguna melakukannya.
Juga batasi concurrency. Satu alur kerja (misalnya sinkronisasi kontak) tidak boleh menghabiskan semua slot worker dan membuat alur kritis seperti login atau checkout kelaparan. Pool terpisah atau batas per-fitur membantu.
Langkah demi langkah: resep integrasi default yang aman
Setiap panggilan pihak ketiga butuh rencana untuk kegagalan. Anda tidak perlu sempurna. Anda butuh perilaku yang dapat diprediksi saat penyedia sedang bermasalah.
1) Klasifikasikan panggilan (harus vs bisa tunggu)
Tentukan apa yang terjadi jika panggilan gagal saat ini. Perhitungan pajak saat checkout mungkin harus-selesai. Sinkron kontak marketing biasanya bisa menunggu. Pilihan ini menentukan semuanya.
2) Tetapkan timeout dan anggaran retry
Pilih timeout per jenis panggilan dan jaga konsistensi. Lalu tetapkan anggaran retry agar Anda tidak terus-menerus memukul API yang lambat.
- Harus-selesai, pengguna menunggu: timeout singkat, 0–1 retry.
- Bisa-tunggu, job latar: timeout lebih lama, beberapa retry dengan backoff.
- Jangan retry selamanya: batasi total waktu per tugas.
3) Amankan retry dengan idempotensi dan pelacakan
Jika permintaan bisa membuat sesuatu atau menagih uang, tambahkan kunci idempotensi dan simpan catatan permintaan. Jika request pembayaran timeout, retry tidak boleh menggandakan tagihan. Pelacakan juga membantu dukungan menjawab, "Apakah ini berhasil?"
4) Tambahkan circuit breaker dan perilaku fallback
Saat error melonjak, hentikan pemanggilan penyedia untuk periode singkat. Untuk panggilan harus-selesai, tampilkan jalur "Coba lagi" yang jelas. Untuk panggilan bisa-tunggu, antre pekerjaan dan proses nanti.
5) Monitor yang dasar
Lacak latensi, tingkat error, dan event open/close breaker. Beri alert pada perubahan yang berkelanjutan, bukan sekadar blip tunggal.
Kesalahan umum yang mengubah masalah kecil jadi downtime
Sebagian besar outage API tidak dimulai besar. Mereka menjadi besar karena aplikasi Anda bereaksi dengan cara terburuk: menunggu terlalu lama, retry terlalu agresif, dan mengikat worker yang sama yang menjalankan semuanya.
Pola berikut menyebabkan efek berantai:
- Retry setiap kegagalan, termasuk 4xx seperti request tidak valid, auth kadaluarsa, atau izin hilang.
- Menetapkan timeout sangat panjang "untuk aman," yang diam-diam menghabiskan thread, koneksi DB, atau job runner sampai kapasitas habis.
- Retry aksi pembuatan tanpa kunci idempotensi, menyebabkan double charge, pengiriman ganda, atau catatan duplikat.
- Pemutus sirkuit salah konfigurasi yang tidak pernah pulih atau terus-flap buka/tutup.
- Menganggap outage parsial sebagai kegagalan total alih-alih menurunkan fitur yang terpengaruh.
Perbaikan kecil mencegah outage besar: retry hanya error yang kemungkinan sementara (timeout, beberapa 429, beberapa 5xx) dan batasi percobaan dengan backoff dan jitter; jaga timeout singkat dan disengaja; wajibkan idempotensi untuk operasi yang membuat/menagih; dan desain untuk outage parsial.
Daftar cepat sebelum rilis
Sebelum push integrasi ke produksi, lakukan pemeriksaan cepat dengan pola pikir kegagalan. Jika Anda tidak bisa menjawab "ya" pada item, anggap itu sebagai blocker rilis untuk alur inti seperti signup, checkout, atau pengiriman pesan.
- Batas waktu eksplisit (connect timeout dan read/response timeout).
- Retry dibatasi (anggaran retry kecil, backoff, jitter, dan batas waktu total).
- Retry aman untuk aksi nyata (kunci idempotensi atau pengecekan deduplikasi yang jelas).
- Ada breaker dan Plan B (fallback, mode terdegradasi, atau antrean).
- Anda bisa mendeteksi masalah lebih awal (latensi, tingkat error, dan kesehatan dependency per penyedia dan endpoint).
Jika penyedia pembayaran mulai timeout, perilaku yang benar adalah "checkout tetap terbuka, pengguna mendapat pesan jelas, dan Anda tidak menggantung selamanya," bukan "semua tergantung sampai timeout."
Contoh: melindungi checkout saat penyedia tidak stabil
Bayangkan checkout yang memanggil tiga layanan: API pembayaran untuk men-charge kartu, API pajak untuk menghitung pajak, dan API email untuk mengirim struk.
Panggilan pembayaran adalah satu-satunya yang harus sinkron. Masalah pada pajak atau email tidak boleh melumpuhkan pembelian.
Saat API pajak lambat
Misalnya API pajak kadang memakan 8–15 detik. Jika checkout menunggu, pengguna meninggalkan keranjang dan app mengikat worker.
Alur yang lebih aman:
- Tetapkan timeout tegas (misalnya 800ms sampai 2s) dan gagal cepat.
- Retry maksimal sekali, hanya jika aman, dengan jitter.
- Jika timeout tercapai, gunakan tarif cache atau tabel terakhir untuk wilayah pembeli.
- Jika secara hukum Anda tidak bisa menggunakan tarif cache, tempatkan pesanan sebagai "pending tax" dan antre perhitungan ulang.
Hasil: lebih sedikit keranjang yang ditinggalkan dan lebih sedikit pesanan macet ketika penyedia pajak lambat.
Saat API email down
Email struk penting, tapi tidak boleh memblokir capture pembayaran. Jika API email gagal, pemutus sirkuit harus terbuka setelah beberapa kegagalan cepat dan menghentikan panggilan selama jendela cooldown singkat.
Alih-alih mengirim email secara inline, antre job "kirim struk" dengan kunci idempotensi (misalnya order_id + email_type). Jika penyedia down, antrean retry di latar dan pelanggan tetap melihat pembelian sukses.
Hasil: lebih sedikit tiket dukungan dari konfirmasi yang hilang, dan tidak ada pendapatan yang hilang karena checkout gagal karena alasan non-pembayaran.
Langkah berikutnya: terapkan ini secara aman di seluruh aplikasi
Pilih satu alur kerja yang paling menyakitkan ketika rusak (checkout, signup, penagihan) dan jadikan referensi integrasi Anda. Lalu salin default yang sama ke mana-mana.
Urutan rollout sederhana:
- Tetapkan timeout dan gagal cepat dengan pesan jelas.
- Tambahkan retry dengan backoff, tapi hanya untuk error yang bisa di-retry.
- Tambahkan idempotensi sehingga retry tidak menggandakan tagihan atau pembuatan.
- Tambahkan circuit breaker sehingga penyedia buruk tidak bisa membuat alur kerja inti macet.
Tuliskan default Anda dan jaga agar membosankan: satu connect timeout, satu request timeout, jumlah retry maksimal, rentang backoff, cooldown breaker, dan aturan untuk apa yang bisa di-retry.
Lakukan drill kegagalan sebelum memperluas ke alur berikutnya. Paksa timeout (atau blokir penyedia di lingkungan pengujian), lalu pastikan pengguna melihat pesan berguna, jalur fallback bekerja, dan retry antrean tidak menumpuk selamanya.
Jika Anda membangun produk baru dengan cepat, layak menjadikan default keandalan ini sebagai templat yang dapat dipakai ulang. Untuk tim yang menggunakan Koder.ai (koder.ai), itu sering berarti mendefinisikan timeout, retry, idempotensi, dan aturan breaker sekali, lalu menerapkan pola yang sama di layanan baru saat Anda menghasilkan dan iterasi.
Pertanyaan umum
Mengapa API pihak ketiga yang lambat dapat membuat aplikasi saya tidak berfungsi?
Tetapkan batas waktu koneksi dan baca yang eksplisit untuk setiap panggilan. Pilih batas singkat untuk alur yang dihadapi pengguna, lalu berikan hasil yang jelas atau pindahkan pekerjaan yang tidak penting ke antrean.
Galat API mana yang sebaiknya saya coba ulang?
Coba lagi permintaan yang mengalami batas waktu, koneksi terputus, dan beberapa galat 5xx karena masalahnya mungkin cepat teratasi. Jangan coba lagi permintaan tidak valid, kredensial salah, galat izin, atau endpoint yang tidak ditemukan.
Berapa kali saya sebaiknya mencoba ulang permintaan API?
Batasi jumlah percobaan ulang, biasanya satu hingga tiga percobaan total. Gunakan backoff eksponensial dengan jitter acak dan batasi total waktu yang dihabiskan untuk mencoba ulang.
Bagaimana cara mencegah tagihan ganda saat permintaan pembayaran mengalami batas waktu?
Gunakan kunci idempotensi untuk tindakan yang membuat catatan, mengirim pesan, menerbitkan pengembalian dana, atau menagih uang. Gunakan kembali kunci yang sama untuk setiap percobaan dari satu tindakan pengguna.
Apa fungsi circuit breaker?
Circuit breaker sementara menghentikan panggilan setelah kegagalan atau batas waktu berulang. Ini melindungi worker Anda dan memberi penyedia waktu untuk pulih sebelum Anda kembali mengirim permintaan uji terbatas.
Apa yang sebaiknya saya pindahkan ke antrean latar belakang?
Jaga checkout dan login tetap responsif dengan memisahkan panggilan opsional. Antrekan email tanda terima, pembaruan CRM, dan analitik alih-alih menunggunya selama permintaan pengguna.
Bagaimana aplikasi saya harus menangani respons batas laju 429?
Patuhi nilai Retry-After dari penyedia jika tersedia, kurangi konkurensi, dan tambahkan jitter sebelum mencoba ulang. Cache atau gabungkan pembacaan yang aman agar aplikasi Anda membuat lebih sedikit panggilan.
Apa yang seharusnya dilihat pengguna saat layanan eksternal gagal?
Tampilkan status sebenarnya: selesai, tertunda, atau gagal. Beri pengguna langkah praktis berikutnya, seperti mencoba ulang pembayaran atau memeriksa pesanan yang tertunda nanti.
Apa yang sebaiknya saya pantau untuk API pihak ketiga?
Lacak latensi, tingkat galat, tingkat batas waktu, respons batas laju, dan peristiwa circuit breaker untuk setiap penyedia dan endpoint. Buat peringatan untuk perubahan yang berkelanjutan agar Anda mendeteksi masalah lebih awal.
Bagaimana cara menguji integrasi API sebelum rilis?
Uji batas waktu, respons parsial, 429, galat 5xx, dan permintaan tulis berulang. Pastikan fallback Anda berfungsi, pekerjaan yang diantrekan tetap terbatas, dan percobaan ulang tidak menduplikasi pekerjaan.