Konteks dan arahan
Sebuah permintaan API memanggil layanan gRPC pengguna, katalog, dan rekomendasi secara berurutan. Pengguna dapat berpindah halaman saat panggilan rekomendasi berjalan lambat. Sistem harus membatasi latensi end-to-end, melepaskan sumber daya server, menghindari amplifikasi retry, dan menjaga operasi tulis tetap dapat di-query ketika pembatalan terjadi setelah adanya efek samping eksternal.
Panduan gRPC mendefinisikan deadline sebagai batas atas waktu tunggu klien dan menjelaskan DEADLINE_EXCEEDED; pembatalan menghentikan RPC yang tidak lagi diperlukan. Jawaban yang kuat memisahkan propagasi anggaran, batas retry, pembersihan stream, dan hasil yang tidak diketahui alih-alih menetapkan batas waktu (timeout) lima detik independen pada setiap lapisan.
Apa yang dinilai oleh pewawancara
Cari deadline absolut atau sisa anggaran, propagasi ke RPC anak dan database, retry yang menggunakan total anggaran yang sama, dan penolakan untuk menyimpulkan bahwa "tidak ada respons" berarti "operasi tulis tidak terjadi." Kandidat juga harus menyebutkan field yang dapat diobservasi dan rencana pengujian injeksi kegagalan (failure-injection).
Pertanyaan klarifikasi
- Apa SLO tingkat atas, deadline klien, dan kebijakan hasil parsial?
- Apakah ketiga panggilan tersebut bersifat read-only, atau mencakup pembayaran dan efek samping lainnya?
- Status mana yang dapat di-retry, dan apakah ada kunci idempotensi?
- Bisakah pesan stream diputar ulang (replayed), dan apakah ada kursor atau nomor urut?
- Apakah database dan API eksternal menerima pembatalan?
- Setelah pembatalan, apakah kontraknya berupa pencarian status, kompensasi, atau rekonsiliasi?
Jawaban 30 detik
"Buat satu deadline absolut di edge; panggilan anak hanya mewarisi sisa anggaran. Propagasikan pembatalan ke setiap RPC, database, dan worker yang dapat dibatalkan. Retry hanya kegagalan transien yang aman dengan batas percobaan, backoff, jitter, dan total deadline yang sama. Operasi tulis menggunakan ID operasi atau pencarian status, bukan retry buta baru. Panggilan streaming menutup iterator dan koneksi, serta log mencatat sisa anggaran, alasan pembatalan, percobaan, dan status akhir."
Solusi langkah demi langkah
Langkah 1: Tentukan anggaran waktu end-to-end
Perlakukan deadline klien sebagai batas atas. Setiap layanan menghitung remaining = deadline - now, menetapkan deadline anak tidak lebih lambat dari titik tersebut, dan mencadangkan waktu untuk antrean, serialisasi, dan penanganan respons.
parent_deadline = 2.0s from request start
child_deadline = min(parent_deadline, now + remaining_budget)Jangan memberikan tambahan dua detik untuk setiap lapisan: rantai tiga hop dapat melebihi enam detik. Gunakan monotonic clock secara lokal untuk pengukuran antrean dan kerja sementara framework RPC membawa deadline.
Langkah 2: Propagasikan pembatalan dan hentikan pekerjaan
Navigasi pengguna, pembatalan eksplisit, dan berakhirnya deadline harus mencapai handler server. Teruskan token pembatalan handler ke database, klien HTTP, antrean tunggu, dan iterator stream. Mengembalikan error sementara pekerjaan latar belakang terus berjalan adalah kebocoran sumber daya.
Pembatalan harus melepaskan koneksi, file sementara, dan lock; berhenti memproduksi pesan baru; serta mencatat tahapan yang telah selesai. Pembatalan tidak dapat membatalkan transaksi yang sudah di-commit, sehingga diperlukan pencarian status atau kompensasi di kemudian hari.
Langkah 3: Lakukan retry di dalam sisa anggaran
Retry hanya error yang secara eksplisit bersifat transien seperti UNAVAILABLE, dengan batas percobaan maksimum, exponential backoff, dan jitter. Setiap percobaan menggunakan deadline yang sama; berakhirnya waktu akan melewati sisa percobaan.
for attempt in 1..maxAttempts:
if remaining(deadline) <= backoff: stop
result = call(child, deadline, cancellation)
if result is success or permanent_error: return result
sleep(jittered_backoff, cancellation)
return DEADLINE_EXCEEDEDPilih satu pemilik retry di seluruh rantai panggilan. Lacak amplifikasi retry dan percobaan per lapisan sehingga proxy dan klien tidak melipatgandakan pekerjaan.
Langkah 4: Pisahkan operasi baca dari operasi tulis
Operasi baca dapat di-retry jika kontrak mengizinkannya. Operasi tulis membutuhkan ID operasi, unique constraint, dan pencarian status. Jika pembatalan terjadi setelah penulisan eksternal, pemanggil memiliki hasil UNKNOWN dan tidak boleh langsung membuat ID baru.
PENDING -> CONFIRMED
\-> FAILED
\-> UNKNOWN (reconcile before retry)Endpoint status mengembalikan hasil dari pihak yang berwenang (authority). Deadline mengontrol waktu tunggu; deadline tidak menciptakan rollback atomik di seluruh sistem.
Langkah 5: Tangani siklus hidup RPC streaming
Tetapkan total deadline dan, jika sesuai, batas waktu idle (idle timeout). Periksa pembatalan pada setiap pembacaan. Saat klien pergi, hentikan pembuatan pesan dan tutup kursor database atau langganan. Sambungkan kembali dengan kursor atau nomor urut daripada memutar ulang efek samping dari awal.
Catat waktu pesan terakhir, alasan pembatalan, penyambungan ulang, dan backlog. Selama graceful shutdown, biarkan stream aktif selesai dalam sisa deadline-nya atau kembalikan status pembatalan yang dapat dikenali.
Langkah 6: Verifikasi propagasi dan batas sumber daya
Uji pembatalan induk, timeout setiap anak, kerja database yang lambat, UNAVAILABLE transien, error permanen, gangguan stream, hilangnya respons setelah operasi tulis, retry multi-lapisan, dan penghentian server secara graceful. Pastikan anak berhenti sebelum deadline induk, pembatalan tidak meninggalkan pekerjaan latar belakang, dan percobaan tetap berada dalam anggaran.
Catat metode RPC, trace ID, sisa deadline, percobaan, status, sumber pembatalan, dan ID operasi tanpa payload sensitif. Uji beban harus mengamati koneksi, antrean, amplifikasi retry, CPU, dan tail latency alih-alih hanya rata-rata keberhasilan.
Contoh jawaban model
"Saya membuat deadline absolut di edge dan mempropagasikan sisa anggaran ke ketiga layanan. Setiap handler meneruskan pembatalan ke database, panggilan HTTP, dan iterator stream-nya serta melepaskan sumber daya sebelum kembali. Panggilan baca me-retry hanya error transien yang aman, dengan satu total deadline dan jitter berbatas."
"Operasi tulis membawa ID operasi; setelah pembatalan saya menandai hasilnya sebagai UNKNOWN dan melakukan query status. Stream menggunakan total deadline, kursor, dan kebijakan penyambungan ulang. Saya menginjeksikan pembatalan induk, timeout anak, respons yang hilang, dan graceful stop, lalu memverifikasi tidak ada kebocoran atau amplifikasi retry."
Kesalahan umum
- Mereset timeout penuh di setiap lapisan → rantai melebihi SLO edge → propagasikan satu deadline absolut.
- Kembali dari handler dan menganggapnya dibatalkan → pekerjaan downstream masih berjalan → propagasikan pembatalan dan lakukan pembersihan.
- Me-retry setiap error → beban teramplifikasi → lakukan retry berdasarkan semantik, anggaran, dan batas percobaan.
- Membuat ID tulis baru setelah timeout → penulisan pertama mungkin telah berhasil → query authority atau lakukan kompensasi.
- Menyambungkan kembali stream dari awal → pesan dan efek samping terduplikasi → gunakan kursor, urutan, dan konsumen yang idempoten.
- Hanya mencatat log error akhir → tidak ada lapisan yang menjelaskan habisnya anggaran → catat log sisa deadline dan percobaan per hop.
Pertanyaan lanjutan dan tanggapan
Pertanyaan lanjutan 1: Bolehkah layanan anak memperpanjang deadline induk?
Tidak. Jika operasi membutuhkan waktu lebih lama, buat menjadi asinkron dan kembalikan ID operasi. Memperpanjang permintaan sinkron secara diam-diam menggagalkan SLO edge.
Pertanyaan lanjutan 2: Bisakah pembatalan membatalkan transaksi database yang sudah di-commit?
Tidak secara andal. Pembatalan menghentikan pekerjaan yang belum dimulai atau belum selesai; pekerjaan yang sudah di-commit memerlukan pencarian status, kompensasi, atau rekonsiliasi. API harus mengekspos state yang dapat diobservasi.
Pertanyaan lanjutan 3: Bagaimana Anda mencegah retry ganda?
Tetapkan satu pemilik retry dan biarkan lapisan lain mempropagasikan error. Bagikan field percobaan dan total anggaran, batasi percobaan, dan pantau amplifikasi di setiap lapisan.
Pertanyaan lanjutan 4: Haruskah stream yang idle selalu dibatalkan?
Bedakan stream berdurasi panjang yang disengaja dari yang ditinggalkan. Gunakan total deadline, idle timeout, atau heartbeat dan kembalikan state yang dapat disambungkan kembali daripada menahan sumber daya selamanya.
Pertanyaan lanjutan 5: Bagaimana jika server terus melakukan komputasi setelah deadline berakhir?
Buat handler dan pekerjaan downstream sadar akan pembatalan (cancellation-aware). Pindahkan pekerjaan yang tidak dapat dibatalkan ke antrean latar belakang berbatas dengan ID operasi dan batas sumber daya, daripada membiarkan thread permintaan tetap terpakai.