Petunjuk dan ruang lingkup
Klien mengirimkan perintah pembuatan pesanan. Server mungkin telah meng-commit pesanan, lalu kehilangan koneksi sebelum mengirim respons. Klien tidak dapat mengetahui hasilnya dan mencoba lagi dengan Idempotency-Key yang sama. Rancang kontrak permintaan, catatan yang tahan lama (durable record), kontrol konkurensi, dan alur pemulihan, serta nyatakan kegagalan mana yang aman untuk dicoba lagi. Keterampilan intinya adalah batasan efek samping, atomisitas, dan status kegagalan yang dapat dijelaskan, jadi topik ini termasuk dalam backend.
Apa yang dievaluasi pewawancara
Jawaban yang kuat memisahkan antara "permintaan tidak pernah tiba", "selesai tetapi respons hilang", dan "masih diproses", lalu memilih pemutaran ulang (replay), pencarian status, atau respons sedang diproses. Jawaban tersebut juga mencakup kunci-sama/parameter-berbeda, permintaan pertama yang bersamaan, kegagalan penyimpanan, kedaluwarsa, perutean multi-wilayah, dan efek hilir alih-alih hanya mengatakan "simpan kuncinya di Redis".
Pertanyaan untuk diklarifikasi terlebih dahulu
- Apakah kunci dibuat oleh klien untuk satu perintah logis, atau diturunkan oleh server dari bidang bisnis?
- Bidang permintaan mana yang terikat pada kunci, dan kesalahan apa yang merepresentasikan ketidakcocokan?
- Apakah penulisan pesanan dan catatan idempotensi berada dalam satu transaksi basis data? Apakah pembayaran memiliki kontrak idempotensi tersendiri?
- Berapa lama klien dapat menunggu, berapa lama kunci disimpan, dan dapatkah kedaluwarsa membuat pesanan kedua?
- Apakah layanan ini satu wilayah atau multi-wilayah, dan penyimpanan mana yang bersifat otoritatif untuk setiap jalur masuk?
Kerangka jawaban 30 detik
"Klien membuat satu kunci stabil untuk satu perintah logis dan menggunakannya kembali pada percobaan ulang. Server memberlakukan batasan keunikan yang tahan lama atas tenant, operasi, dan kunci, menyimpan sidik jari permintaan, status, dan respons akhir. Permintaan pertama secara atomik mengklaim processing dan menjalankan transaksi pesanan; permintaan dengan kunci-sama/parameter-sama menunggu atau diputar ulang, sedangkan ketidakcocokan ditolak. Setelah crash, pulihkan dari transaksi dan bukti hilir. Kueri efek samping yang tidak diketahui sebelum melakukan kompensasi, jangan pernah mencoba lagi secara membabi buta. Retensi harus mencakup jendela percobaan ulang, dan metrik harus membuktikan nol efek samping duplikat."
Solusi langkah demi langkah
Kontrak harus mewajibkan kunci yang tidak kosong dan memiliki batas panjang yang tetap tidak berubah di seluruh percobaan ulang dari satu perintah logis. Server menyimpan (tenant_id, operation, idempotency_key) unik bersama dengan hash permintaan yang dinormalisasi, status, ID sumber daya, kode respons, badan respons, dan kedaluwarsa. Hash mencegah penggunaan kembali kunci yang sama secara tidak sengaja untuk perintah yang berbeda.
Permintaan pertama harus memasukkan catatan processing yang tahan lama dan membuat pesanan dalam satu transaksi lokal, atau menggunakan log transaksi yang secara jelas menghubungkan keduanya. Pada konflik keunikan, baca catatan yang ada: putar ulang respons yang disimpan untuk succeeded, kembalikan kesalahan bisnis yang sama untuk failed, dan tunggu sebentar atau kembalikan status sedang diproses untuk processing. Kunci dalam memori (in-memory lock) saja akan gagal saat restart dan di seluruh replika.
Konkurensi diputuskan oleh batasan keunikan dan pembaruan bersyarat. Hanya permintaan yang memiliki catatan pembuatan yang boleh memindahkan processing ke succeeded; sertakan versi atau status yang diharapkan dalam pembaruan sehingga dua worker tidak dapat melakukan commit. Jika transaksi pesanan berhasil sebelum proses mengalami crash, percobaan ulang akan membaca succeeded dan memutarnya kembali. Jika transaksi di-rollback, percobaan ulang dapat dieksekusi dengan aman.
Efek hilir menciptakan jendela waktu di mana hasil lokal tidak diketahui sementara efek jarak jauh mungkin telah berhasil. Pembayaran, pengiriman, dan pesan harus menggunakan ID operasi bisnis yang sama dengan kontrak idempotensi hilir, serta mempertahankan permintaan dan hasilnya. Tanpa idempotensi hilir, lakukan kueri rekonsiliasi atau publikasikan melalui outbox dan coba lagi dari worker; jangan pernah menagih lagi hanya karena panggilan lokal mengalami timeout.
Catatan yang sedang diproses membutuhkan pemulihan. Simpan lease dan heartbeat; worker pemulihan memeriksa transaksi pesanan, status hilir, atau log transaksi sebelum melangkah ke status akhir. Jika bukti tidak cukup, tandai unknown dan kirimkan ke rekonsiliasi daripada memperlakukannya sebagai kegagalan. Mesin status tidak boleh memindahkan succeeded kembali ke processing.
Kedaluwarsa harus sesuai dengan risiko bisnis. Simpan catatan selama masa percobaan ulang maksimum klien, antrean percobaan ulang jaringan, dan jendela kompensasi. Menggunakan kembali kunci yang kedaluwarsa harus mengembalikan key_expired yang eksplisit, bukan secara diam-diam membuat pesanan kedua. Badan respons lama hanya dapat dipadatkan jika ringkasan audit dan keunikan tingkat sumber daya tetap dipertahankan.
Dalam penerapan multi-wilayah, rute kunci logis ke satu penyimpanan otoritatif atau terapkan batasan keunikan global dengan replikasi sinkron. Jangan mengeksekusi lagi di replika lain hanya karena pembacaan processing tertunda. Ukur konflik kunci, konflik parameter, timeout proses berjalan, respons pemutaran ulang, status tidak diketahui, pemblokiran sumber daya duplikat, dan perbedaan rekonsiliasi.
Contoh jawaban berkualitas tinggi
"Saya mendefinisikan kunci idempoten sebagai identitas stabil dari satu perintah pembuatan logis, bukan ID permintaan baru pada setiap percobaan ulang HTTP. Server memberlakukan batasan keunikan yang tahan lama atas tenant, operasi, dan kunci, menyimpan hash permintaan, status, ID sumber daya, respons, dan kedaluwarsa. Permintaan pertama secara atomik mengklaim processing dan membuat pesanan; permintaan dengan kunci-sama/parameter-sama diputar ulang atau menunggu, dan ketidakcocokan ditolak.
Saya menyimpan penulisan pesanan dan catatan idempotensi dalam satu transaksi dan meneruskan ID operasi yang sama ke pembayaran atau efek hilir lainnya. Jika respons hilang, percobaan ulang membaca hasil yang disimpan; jika status lokal tidak diketahui, saya mengueri catatan hilir dan rekonsiliasi alih-alih menebak dengan POST lain. Worker dengan sistem lease memulihkan processing yang macet, dan transisi bersyarat hanya mengarah ke succeeded, failed, atau unknown. Retensi mencakup masa percobaan ulang dan kompensasi. Saya menyimulasikan permintaan pertama yang bersamaan, crash proses, respons yang hilang, dan keterlambatan lintas wilayah, serta memastikan nol pesanan atau tagihan duplikat."
Kesalahan umum
- Menghasilkan kunci baru untuk setiap percobaan ulang → server tidak dapat mengidentifikasi satu perintah logis → gunakan kembali kunci asli.
- Hanya menggunakan penguncian dalam memori atau host tunggal → restart dan replika kehilangan deduplikasi → terapkan keunikan yang tahan lama.
- Memutar ulang hasil untuk muatan (payload) yang berbeda → menyembunyikan bug klien → simpan sidik jari dan tolak ketidakcocokan.
- Memanggil layanan hilir segera setelah merekam
processing→ crash membuat efek tidak dapat diketahui → gunakan transaksi, outbox, atau idempotensi hilir. - Menagih lagi setelah timeout → penagihan jarak jauh mungkin telah berhasil → kueri dan rekonsiliasi terlebih dahulu.
- Memperlakukan catatan yang macet sebagai gagal dan menjalankannya kembali → membuat sumber daya kedua → kumpulkan bukti dalam pemulihan.
- Mengedaluwarsa kunci terlalu cepat → percobaan ulang yang tertunda membuat duplikat → selaraskan retensi dengan risiko dan jendela percobaan ulang.
- Hanya menguji panggilan serial → kondisi race tetap menyebabkan penulisan ganda → uji konkurensi dengan kunci yang sama, crash, dan perutean multi-wilayah.
Pertanyaan lanjutan dan tanggapan
Pertanyaan lanjutan 1: Mengapa tidak menggunakan ID pesanan sebagai kunci unik?
ID pesanan biasanya baru ada setelah server membuat sumber daya, sehingga tidak dapat mencakup jendela waktu sebelum respons pertama dikirim. Kunci idempoten ada sebelum efek samping terjadi dan mengikat percobaan ulang ke satu perintah logis.
Pertanyaan lanjutan 2: Bagaimana jika muatan berubah dengan kunci yang sama?
Buat hash dari badan permintaan yang dinormalisasi dan header yang relevan. Sidik jari yang berbeda akan mengembalikan kesalahan konflik parameter tanpa menimbulkan efek samping baru; klien harus membuat kunci baru untuk perintah baru.
Pertanyaan lanjutan 3: Bagaimana jika permintaan pertama tetap berada di processing selamanya?
Gunakan lease, heartbeat, dan pemindaian timeout. Worker pemulihan memeriksa transaksi lokal, hasil hilir, dan log pesan; hanya bukti yang cukup yang dapat memajukan status, jika tidak maka status menjadi unknown untuk rekonsiliasi.
Pertanyaan lanjutan 4: Bisakah Redis menjadi satu-satunya penyimpanan idempotensi?
Jika basis data memiliki efek samping tersebut, penggusuran (eviction) data di Redis, kegagalan, atau jeda replikasi dapat menghilangkan batas keamanan. Redis dapat mengoordinasikan pekerjaan jangka pendek, tetapi status akhir dan keunikan harus berada di penyimpanan tahan lama yang konsisten dengan penulisan bisnis.
Pertanyaan lanjutan 5: Apa yang harus terjadi setelah kunci kedaluwarsa?
Jangan menerima kunci lama secara diam-diam. Kembalikan kesalahan kedaluwarsa dan arahkan klien untuk mengueri pesanan asli atau membuat perintah baru; keunikan bisnis tingkat sumber daya harus memberikan perlindungan tambahan.
Pertanyaan lanjutan 6: Bagaimana Anda membuktikan tidak adanya efek duplikat?
Kirim kunci yang sama secara bersamaan, matikan proses sebelum dan sesudah commit, hilangkan respons, dan buat panggilan hilir mengalami timeout. Periksa keunikan sumber daya, ID operasi, respons yang diputar ulang, log transisi status, dan rekonsiliasi. Asersinya adalah paling banyak satu efek samping yang berhasil per kunci logis.
Pertanyaan lanjutan 7: Apakah kunci idempoten merupakan pemrosesan tepat satu kali (exactly-once)?
Tidak. Kunci ini membuat satu layanan mengenali perintah duplikat; kunci ini tidak membuat jaringan lintas layanan menjadi tepat satu kali (exactly-once). Transaksi, pengiriman outbox, idempotensi hilir, kueri, dan rekonsiliasi tetap diperlukan, dengan hasil unknown yang eksplisit.