Prompt dan Kapan Pertanyaan Ini Berlaku
Sebuah API checkout memanggil layanan pajak pihak ketiga secara sinkron. Dependensi tersebut biasanya memiliki p50 sebesar 80 ms dan p99 sebesar 180 ms, tetapi terkadang mengalami kegagalan koneksi, respons lambat, HTTP 429, 503, dan kasus di mana permintaan mungkin telah mencapai server tetapi responsnya hilang. API checkout memiliki target end-to-end sebesar 800 ms. Rantai panggilan layanan bisa sedalam lima lapisan, dan beberapa SDK mungkin sudah melakukan retry secara default.
Rancang kebijakan pemanggilan tersebut. Jelaskan cara membagi deadline ke dalam timeout per percobaan, kegagalan mana yang dapat di-retry, cara mengatur jumlah percobaan maksimum, exponential backoff, dan jitter, bagaimana circuit breaker terbuka dan pulih, serta bagaimana isolasi, degradasi, metrik, dan fault injection membuktikan bahwa kegagalan lokal tidak akan menjadi kegagalan beruntun (cascading failure).
Latensi dan kedalaman rantai panggilan adalah asumsi wawancara. Keahlian intinya adalah semantik kegagalan, perlindungan sumber daya, dan kontrol pemulihan untuk panggilan antar-layanan yang sinkron, sehingga kategorinya adalah backend. Pertanyaan pesanan idempoten yang sudah ada berfokus pada kontrak basis data untuk satu operasi write. Pertanyaan ini menggunakan idempotensi hanya untuk memutuskan apakah aman melakukan retry setelah timeout; fokus utamanya adalah anggaran waktu dan beban di seluruh rantai panggilan.
Apa yang Dievaluasi oleh Pewawancara
Sinyal pertama adalah apakah kandidat membuat buku besar waktu (time ledger). Deadline end-to-end 800 ms bukan berarti timeout dependensi sebesar 800 ms. Validasi lokal, antrean, serialisasi, dan pemrosesan respons semuanya membutuhkan anggaran waktu. Setiap percobaan juga harus memperhitungkan fase koneksi, TLS, dan respons, dan retry berikutnya hanya boleh dimulai jika sisa waktu masih mencukupi.
Sinyal kedua adalah melakukan retry berdasarkan semantik kegagalan. Kegagalan sebelum koneksi terbentuk, 503 sementara, atau 429 dengan panduan retry mungkin dapat di-retry. Parameter yang salah, autentikasi, dan otorisasi tidak akan membaik seiring berjalannya waktu. Ketika operasi write mengalami timeout setelah dikirim, hasilnya mungkin "sudah ter-commit tetapi respons tidak diketahui". Kunci idempotensi yang stabil, pengecekan status, atau proses rekonsiliasi diperlukan sebelum aman untuk melakukan retry.
Sinyal ketiga adalah amplifikasi retry (retry amplification). Jika setiap layanan dalam rantai sedalam lima lapisan melakukan hingga tiga percobaan, dependensi terbawah dapat menerima panggilan sebanyak 3^5 = 243 kali. Retry harus berada pada satu lapisan yang memahami batas waktu bisnis, dengan batasan pada jumlah percobaan, total waktu yang telah berlalu, dan anggaran retry berbasis token.
Terakhir, pewawancara menginginkan loop pemulihan. Timeout membatasi durasi satu kali tunggu, retry menangani kegagalan singkat, circuit breaker menolak panggilan selama kegagalan berkepanjangan, dan bulkhead membatasi konkurensi serta penggunaan antrean. Jawaban yang kuat juga membatasi probe setengah terbuka (half-open probes), menolak fallback yang tidak jujur, dan mengamati panggilan logis secara terpisah dari percobaan fisik.
Pertanyaan untuk Diklarifikasi Sebelum Menjawab
- Apakah panggilan dependensi berupa read atau write dengan efek samping? Read biasanya dapat diulang. Write yang mengalami timeout mungkin memiliki hasil yang belum diketahui dan memerlukan kunci idempotensi, pengecekan status, atau rekonsiliasi.
- Apakah 800 ms merupakan batas waktu mutlak (hard deadline) atau target observasional? Di sini, ini adalah titik di mana pemanggil tidak lagi menunggu. Pembatalan harus diteruskan ke downstream agar pekerjaan tidak diselesaikan untuk pemanggil yang sudah tidak ada.
- Error mana yang dinyatakan dapat di-retry oleh dependensi? Klasifikasi harus mengikuti protokol dan kontrak vendor, terutama
Retry-Afterpada 429, 503, kegagalan koneksi, dan business error. "Apa pun selain 200" bukanlah sebuah kebijakan. - Apakah SDK, proxy, atau service mesh sudah melakukan retry? Buat inventaris default dan batas percobaan di setiap lapisan. Satu retry aplikasi yang terlihat dapat berlipat ganda menjadi badai retry (retry storm).
- Bagaimana distribusi latensi dan kapasitas dependensi? Tentukan timeout dari persentil, tingkat false-timeout yang dapat ditoleransi, dan toleransi jaringan, lalu validasi koneksi baru, lalu lintas lintas-wilayah, dan beban puncak.
- Degradasi mana yang dapat diterima? Jika kalkulasi pajak memiliki persyaratan kepatuhan (compliance), membuat nilai pajak default "sukses" palsu adalah tindakan berbahaya. Kegagalan eksplisit, peninjauan manual, atau penundaan checkout harus mengikuti kontrak bisnis.
- Apa batas isolasi circuit breaker? Gunakan vendor, wilayah, endpoint, atau operasi yang independen. Satu shard yang gagal tidak boleh memutus sumber daya yang sehat.
Kerangka Jawaban 30 Detik
"Saya akan membagi deadline end-to-end 800 ms menjadi anggaran waktu dan meneruskan batas waktu absolut ke downstream. Setiap panggilan memiliki timeout koneksi dan permintaan, dan percobaan lain hanya dimulai jika sesuai dengan sisa anggaran waktu. Saya mengklasifikasikan kegagalan berdasarkan keterpulihan dan apakah efek samping diketahui: patuhi panduan server untuk 429, retry hanya kegagalan koneksi singkat dan respons 5xx tertentu, serta memerlukan idempotensi atau rekonsiliasi status saat hasil write tidak diketahui. Retry berada di satu lapisan, menggunakan paling banyak dua percobaan dengan exponential backoff berbatas dan jitter, serta mengonsumsi anggaran token yang membatasi lalu lintas ekstra selama kegagalan. Kegagalan berkepanjangan akan membuka sirkuit dan gagal dengan cepat (fail fast); setelah cooldown, hanya beberapa probe half-open yang diizinkan lewat. Batas konkurensi terpisah dan antrean berbatas melindungi sumber daya lokal. Fault injection kemudian memverifikasi deadline, jumlah percobaan, efek duplikasi, dan jalur pemulihan."
Pembahasan Mendalam Langkah demi Langkah
Mulailah dengan mengubah waktu menjadi anggaran eksplisit. Dalam skenario ini, alokasikan 120 ms dari 800 ms untuk pekerjaan lokal sebelum pemanggilan dependensi dan 100 ms untuk memproses hasilnya. Hal ini menyisakan anggaran dependensi sebesar 580 ms. Salah satu konfigurasi awal yang dapat diuji adalah percobaan pertama yang dibatasi maksimal 220 ms, backoff acak dalam [0, 80) ms, dan percobaan kedua yang dibatasi maksimal 220 ms. Skenario terburuk memakan waktu 520 ms dan menyisakan 60 ms dalam anggaran dependensi. Nilai-nilai ini bukan konstanta universal; nilai produksi harus dikalibrasi dari persentil downstream, false timeout yang dapat ditoleransi, latensi jaringan, dan uji beban.
Teruskan batas waktu absolut atau sisa anggaran yang menurun secara monoton melalui rantai panggilan. Sebelum melakukan retry, hitung ulang remaining. Jika nilainya lebih kecil dari "batas percobaan berikutnya + waktu penyelesaian minimum", kembalikan error daripada memulai panggilan yang tidak dapat selesai. Tentukan semantik timeout koneksi dan permintaan secara tepat, termasuk apakah DNS, TLS, dan waktu tunggu connection-pool sudah tercakup. Instance baru dapat melakukan pemanasan koneksi (warm connections) sebelum menerima lalu lintas agar waktu handshake tidak disalahartikan sebagai dependensi yang lambat. Teruskan pembatalan, dengan tetap berasumsi bahwa pembatalan tersebut bisa saja tiba setelah pihak remote selesai melakukan commit pekerjaan.
Selanjutnya, bangun matriks semantik kegagalan:
| Hasil | Retry? | Prasyarat dan tindakan |
|---|---|---|
| Kegagalan sebelum koneksi terbentuk | Ya | Anggaran masih mencukupi; gunakan backoff dan jitter |
| HTTP 429 | Kondisional | Patuhi Retry-After; waktu tunggu dan percobaan berikutnya harus muat dalam deadline |
| HTTP 503 atau 5xx tertentu | Kondisional | Vendor menyatakannya sebagai masalah sementara dan anggaran retry masih ada |
| HTTP 400, 401, atau 403 | Biasanya tidak | Perbaiki parameter, kredensial, atau izin; menunggu tidak akan memperbaiki permintaan |
| Timeout setelah write dikirim | Jangan pernah secara membabi buta | Gunakan kembali kunci idempotensi atau lakukan query dan rekonsiliasi status operasi |
| Pembatalan oleh pemanggil atau deadline kedaluwarsa | Tidak | Berhenti menambahkan pekerjaan dan kembalikan kegagalan eksplisit |
Tiga gerbang mengontrol setiap retry: error dapat di-retry, waktu yang tersisa cukup, dan anggaran retry memiliki token. Gunakan capped exponential backoff dan randomized jitter untuk mendekorelasikan klien yang gagal bersamaan. Utamakan waktu retry yang diarahkan server jika tersedia. Jumlah percobaan maksimum mencakup panggilan awal; rancangan ini dimulai dengan total dua percobaan. Baca dokumentasi SDK dengan cermat karena maxAttempts = 2 dan "dua kali retry" masing-masing dapat berarti total dua panggilan dan total tiga panggilan.
Lakukan retry pada satu lapisan yang paling memahami batas waktu bisnis. Jika kelima lapisan melakukan tiga percobaan, beban teoritis pada lapisan terbawah akan meningkat sebanyak 243 kali lipat. Lacak downstream_attempts / logical_requests sebagai faktor amplifikasi retry. Nilainya harus mendekati 1 dalam kondisi sehat dan dibatasi secara eksplisit selama terjadi gangguan. Token bucket atau kuota retry yang setara akan berkurang seiring meningkatnya kegagalan, kemudian menjeda retry atau mengizinkannya pada tingkat rendah, sehingga klien berhenti menambah beban saat dependensi sedang sangat rentan.
Bungkus operasi dependensi spesifik dalam sebuah circuit breaker. Status closed (tertutup) mengizinkan panggilan dan mengukur kegagalan serta panggilan lambat melalui sliding window dengan ukuran sampel minimum. Melewati ambang batas akan membuka sirkuit (open). Status open tidak memanggil dependensi dan segera mengembalikan kegagalan yang dapat dikenali atau degradasi yang disetujui bisnis. Setelah masa cooldown, status half-open hanya mengizinkan sejumlah kecil probe konkuren. Keberhasilan probe yang memadai akan menutup sirkuit; kegagalan kritis akan membukanya kembali. Ambang batas berasal dari karakteristik lalu lintas dan pemulihan. "20 panggilan dan 50% kegagalan" adalah contoh, bukan konstanta universal.
Circuit breaker memiliki biaya overhead. State modal membuat pengujian dan pemulihan menjadi lebih kompleks, cooldown yang panjang menunda pemulihan, dan batasan cakupan yang terlalu luas dapat memblokir shard yang sehat. Catat setiap transisi status, batasi konkurensi probe half-open, dan batasi cakupan breaker pada domain kegagalan yang nyata. Untuk kesalahan singkat dan berisiko rendah, timeout yang ketat, retry satu lapisan, dan kuota retry mungkin sudah cukup. Jangan menambahkan breaker hanya demi menerapkan suatu pola desain.
Sumber daya lokal tetap membutuhkan isolasi. Berikan dependensi pajak batas konkurensi, connection pool, dan bounded queue tersendiri agar panggilan lambat tidak menghabiskan setiap thread atau koneksi checkout. Panggilan yang mengantre juga menghabiskan anggaran deadline; buang pekerjaan yang tidak dapat diselesaikan saat keluar dari antrean. Fallback harus jujur dan dapat dijelaskan. "Pajak untuk sementara tidak tersedia" atau alur kerja manual dapat dianggap valid; memperlakukan pajak yang tidak diketahui sebagai nol dan menyatakan checkout berhasil adalah tindakan yang salah.
Uji invarian dalam kondisi gagal. Injeksikan penolakan koneksi, respons lambat 250 ms, 429 dengan nilai Retry-After yang berbeda, 503, 400 yang tidak dapat di-retry, dan kasus "write ter-commit, respons hilang". Pastikan bahwa satu permintaan logis melakukan paling banyak dua percobaan downstream, total latensi tidak melebihi 800 ms, error permanen tidak di-retry, dan write yang tidak diketahui tidak diduplikasi. Kemudian pertahankan kegagalan hingga sirkuit terbuka. Verifikasi penolakan cepat, probe half-open yang terbatas, penutupan sirkuit yang berhasil setelah pemulihan, dan bulkhead yang tidak jenuh.
Metrik produksi harus memisahkan panggilan logis dari percobaan fisik: keberhasilan end-to-end dan p95/p99, hasil dan latensi per percobaan, timeout fase koneksi vs fase permintaan, amplifikasi retry, tingkat pemulihan retry dan latensi tambahan, saldo anggaran retry, status breaker dan jumlah penolakan, hasil probe half-open, konkurensi pool dan kedalaman antrean, ditambah konflik idempotensi dan hasil rekonsiliasi. Keberhasilan akhir saja dapat menyembunyikan sistem yang membeli ketersediaan dengan mengorbankan lalu lintas downstream tiga kali lipat.
Contoh Jawaban Berkualitas Tinggi
"Pertama, saya akan mengonfirmasi bahwa ini adalah pencarian pajak sinkron dan pemanggil berhenti menunggu setelah 800 ms. Jika saya mengalokasikan 120 ms untuk pemrosesan sebelum panggilan dan 100 ms untuk penanganan respons, dependensi mendapatkan 580 ms. Kebijakan awal saya menggunakan total dua percobaan: masing-masing dapat memakan waktu maksimal 220 ms, dengan backoff ber-jitter sebesar [0, 80) ms di antara keduanya. Sebelum setiap percobaan, saya memeriksa sisa deadline yang diteruskan, sehingga antrean yang panjang tidak secara mekanis memicu panggilan kedua.
Kegagalan memerlukan klasifikasi. Kegagalan sebelum koneksi terbentuk dan 503 sementara yang ditentukan vendor dapat di-retry dalam batas anggaran. Kode 429 mengikuti Retry-After, tetapi jika waktu tunggu melebihi deadline, saya langsung menggagalkannya. Saya tidak melakukan retry untuk 400, 401, atau 403. Jika operasi tersebut menulis state, timeout setelah pengiriman berarti hasilnya tidak diketahui. Saya harus menggunakan kembali kunci idempotensi atau melakukan query dan rekonsiliasi status daripada mengirimkan permintaan baru secara membabi buta.
Saya menginventarisasi retry di SDK, gateway, dan service mesh, lalu menempatkan retry pada satu lapisan yang dapat melihat deadline bisnis dan menegakkan anggaran retry token. Tiga percobaan di masing-masing dari lima lapisan dapat memperbesar panggilan terbawah hingga 243 kali, jadi saya memantau rasio percobaan fisik dibagi permintaan logis.
Untuk kegagalan berkepanjangan, saya membatasi cakupan circuit breaker berdasarkan vendor pajak dan operasi. Status closed mengukur tingkat kegagalan dengan sampel minimum, open gagal dengan cepat, dan half-open hanya mengizinkan beberapa probe sebelum pemulihan. Dependensi ini juga mendapatkan pool konkurensi terpisah dan antrean berbatas. Degradasi hanya mengembalikan status eksplisit yang disetujui bisnis; tidak pernah memalsukan pajak bernilai nol.
Terakhir, saya melakukan fault injection untuk memverifikasi batas maksimum dua percobaan, batas 800 ms, tidak adanya retry pada error permanen, tidak ada duplikasi write, dan pemulihan sirkuit melalui probe terbatas. Di lingkungan produksi, saya memantau keberhasilan logis, hasil percobaan, amplifikasi retry, saldo anggaran, status breaker, dan saturasi bulkhead secara bersamaan."
Kesalahan Umum
- Mengatur timeout dependensi ke 800 ms penuh → Tidak ada waktu tersisa untuk penyelesaian lokal, dan dependensi tetap menahan sumber daya setelah pemanggil menyerah → Kurangi anggaran lokal dan jaringan dari batas waktu dan teruskan sisanya.
- Melakukan retry pada setiap respons yang gagal → Kesalahan parameter dan izin tidak dapat sembuh sendiri, sehingga retry hanya menambah beban dan latensi → Klasifikasikan berdasarkan protokol, kode error, dan hasil efek samping.
- Mengaktifkan tiga percobaan di setiap lapisan → Lima lapisan dapat melipatgandakan satu panggilan menjadi 243 percobaan di lapisan terbawah → Lakukan retry pada satu lapisan yang sesuai dan ukur amplifikasinya.
- Mengirim ulang write yang mengalami timeout dengan ID baru → Percobaan pertama mungkin sudah ter-commit, menyebabkan tagihan atau sumber daya ganda → Gunakan kembali kunci idempotensi atau lakukan query dan rekonsiliasi status.
- Menggunakan exponential backoff tanpa jitter atau batasan (cap) → Klien masih dapat melakukan retry dalam gelombang yang tersinkronisasi → Batasi percobaan dan waktu yang berlalu, serta acak durasi penundaan (delay).
- Memperlakukan circuit breaker sebagai pengganti timeout → Panggilan yang sedang berjalan (in-flight) tetap menempati thread, koneksi, dan antrean → Pertahankan timeout per percobaan dan isolasi konkurensi.
- Memulihkan semua lalu lintas segera setelah half-open dimulai → Dependensi yang baru pulih akan kewalahan lagi → Izinkan probe terbatas dan wajibkan bukti pemulihan yang sukses secara eksplisit.
- Menggunakan satu breaker global untuk setiap vendor dan endpoint → Satu gangguan lokal akan memblokir sumber daya lain yang sehat → Batasi cakupan state breaker ke domain kegagalan yang independen.
- Selalu mengembalikan status sukses dari fallback → Data yang tidak diketahui disajikan seolah-olah benar dan merusak semantik bisnis → Gunakan hanya degradasi yang disetujui dengan batasan yang eksplisit.
- Hanya mengamati tingkat keberhasilan akhir → Badai retry dapat menyembunyikan penurunan performa downstream untuk sementara → Amati panggilan logis, percobaan fisik, latensi tambahan, dan saturasi.
Pertanyaan Lanjutan dan Jawabannya
Pertanyaan Lanjutan 1: Berapa kelipatan dari p99 downstream yang harus dijadikan nilai timeout?
Tidak ada kelipatan yang pasti. Pilih tingkat false-timeout yang dapat diterima, mulai dari persentil latensi yang sesuai, dan tambahkan toleransi untuk keterlambatan jaringan, panggilan lintas wilayah, inisiasi koneksi, dan sedikit pergeseran beban. Hasilnya harus tetap muat dalam deadline upstream. Ketika p99 mendekati p50, sedikit pergeseran latensi dapat menyebabkan banyak timeout, sehingga penambahan batas ekstra (padding) mungkin diperlukan. Verifikasi apakah DNS, TLS, dan waktu tunggu connection-pool termasuk dalam penghitungan timer.
Pertanyaan Lanjutan 2: Apakah 429 dan 503 sama-sama dapat di-retry?
Hanya secara kondisional. Utamakan Retry-After untuk 429, tetapi waktu tunggu dan percobaan berikutnya harus sesuai dengan sisa anggaran waktu. Jika tidak, kembalikan kegagalan yang dapat dikenali. Lakukan retry pada 503 hanya jika kontrak vendor menandainya sebagai masalah sementara. Keduanya menghabiskan anggaran retry; jangan sampai sinyal dari server yang kelebihan beban diubah menjadi lalu lintas langsung yang lebih besar.
Pertanyaan Lanjutan 3: Mengapa tingkat pemulihan retry yang tinggi masih dapat mengindikasikan sistem yang tidak sehat?
Keberhasilan akhir mungkin diperoleh dengan beban dan latensi ekstra. Jika 100 panggilan logis menghasilkan 180 percobaan downstream, amplifikasinya adalah 1,8. Ketika dependensi mendekati batas kapasitas, 80% beban ekstra tersebut dapat menunda pemulihan. Evaluasi tingkat pemulihan bersama dengan amplifikasi, latensi percobaan, habisnya anggaran, dan saturasi downstream.
Pertanyaan Lanjutan 4: Apakah Anda masih memerlukan rate limiting atau bulkhead saat sirkuit dalam status open?
Ya. Breaker memblokir panggilan baru ke satu dependensi, tetapi permintaan lokal mungkin sudah berjalan atau mengantre, dan dependensi lain masih dapat mengonsumsi sumber daya. Batas konkurensi, pool terpisah, dan bounded queue mengontrol kapasitas lokal; entry rate limiting mengontrol beban baru yang masuk. Probe half-open juga membutuhkan kuota independen yang kecil daripada kapasitas bersama yang tidak terbatas.
Pertanyaan Lanjutan 5: Apakah bermasalah jika setiap instance mengelola state breaker-nya sendiri?
State dapat berbeda antar-instance, tetapi state yang dibagikan secara ketat (strongly shared) menambah dependensi sinkron lain dan menambah latensi. Desain yang umum memberikan konfigurasi dan state lokal yang sama untuk setiap instance; pada lalu lintas tinggi, setiap instance melihat sampel yang cukup dan sinyal kegagalan menyebar secara alami. Instance bervolume rendah atau domain kegagalan yang dikoordinasikan secara global dapat menggunakan service mesh atau lapisan terpusat. Dalam kedua kasus, nyatakan cakupan, ukuran sampel, dan lalu lintas ekstra maksimum selama kegagalan.
Pertanyaan Lanjutan 6: Kapan arsitektur ini harus diubah menjadi antrean asinkron?
Jika respons HTTP tidak memerlukan hasil pajak secara langsung, atau pemulihan dapat memakan waktu jauh lebih lama daripada deadline pengguna, pemrosesan asinkron lebih cocok. Simpan tugas (persist task), kembalikan status yang dapat di-query, dan biarkan consumer menggunakan kebijakan retry dan dead-letter-nya sendiri. Antrean tidak menghilangkan masalah idempotensi, kedaluwarsa, atau degradasi, tetapi memindahkan proses pemulihan yang lama keluar dari koneksi sinkron dan anggaran 800 ms.
Pertanyaan Lanjutan 7: Bagaimana Anda meluncurkan ini tanpa menyebabkan insiden konfigurasi?
Mulailah dengan mencatat keputusan timeout, retry, dan circuit breaker yang seharusnya dibuat (dry-run), tanpa menambahkan retry nyata atau menolak lalu lintas. Pastikan bahwa SDK tidak menyembunyikan percobaan ekstra. Kemudian lakukan canary berdasarkan vendor atau beberapa instance, batasi anggaran retry global, dan sediakan tombol penonaktifan cepat (fast disable switch). Pantau volume percobaan, tail latency end-to-end, durasi status open, kegagalan half-open, dan kapasitas dependensi sebelum memperluas peluncuran.