Pernah nggak bikin fitur pembayaran, internet user lemot, dia klik tombol “Bayar” 2 kali, eh saldonya kepotong 2 kali juga? 😱
Gunnar Morling baru saja membahas teknik wajib buat backend engineer biar API kita tahan banting terhadap retry. Namanya Idempotency Keys.
Ini bedahannya:
1. ⚠️ Problem Statement (Masalah)
* Network is Unreliable: Di dunia distributed systems, request bisa timeout. Klien tidak tahu apakah request tadi sukses sampai server atau mati di jalan.
* The Retry Trap: Solusi standar klien saat timeout adalah melakukan retry.
* Double Processing: Tanpa pengaman, server yang menerima request retry (padahal request pertama sebenernya sukses tapi timeout responsnya) akan memproses transaksi dua kali. Bahaya buat data sensitif (pembayaran, email blast)!
2. 🛠️ Metodologi & Solusi
Solusinya adalah menerapkan pola Idempotency Key.
* Unique Token: Klien membuat ID unik (biasanya UUID/ULID) untuk setiap intent transaksi. ID ini dikirim via HTTP Header (misal: Idempotency-Key).
* Server Check: Sebelum memproses, server mengecek ke database: “Kunci ini udah pernah diproses belum?”
* Logic Flow:
* Jika New Key ➡️ Proses Transaksi ➡️ Simpan Hasil & Key ➡️ Return Response.
* Jika Existing Key ➡️ Jangan Proses Ulang! ➡️ Ambil hasil yang disimpan sebelumnya ➡️ Return Response.
3. 📈 Findings & Nuansa Teknis
* Race Conditions: Sekadar if (exists) return tidak cukup. Bagaimana jika dua request dengan kunci sama masuk di milidetik yang sama? Kita butuh database constraint (unique index) untuk menangani ini.
* Retention: Kunci tidak perlu disimpan selamanya. Gunakan TTL (Time-To-Live), misalnya 24 jam, untuk menghemat storage.
* Scope: Kunci sebaiknya unik per-user atau per-operasi untuk mencegah collision.
4. 💡 Key Takeaways
* Safety First: API untuk operasi POST atau PATCH (yang mengubah data) wajib hukumnya punya mekanisme ini.
* Client Responsibility: Kunci harus digenerate oleh client, bukan server. Karena client yang tahu kapan dia melakukan “request baru” atau “mengulang request lama”.
* Experience: User nggak perlu takut klik tombol dua kali. Sistem yang resilient menangani duplicate request dengan elegan.
💻 How to Use / Implementation
Ini adalah pola arsitektur, bukan library siap pakai. Berikut logika implementasinya di Backend (misal Java/Go/NodeJS):
* Client Side:
Generate UUID v4 saat user klik tombol aksi.
POST /api/payments
Idempotency-Key: 123e4567-e89b-12d3-a456-426614174000
Body: { amount: 100 }
* Database Schema:
Buat tabel khusus untuk mencatat log request.
CREATE TABLE idempotent_requests (
key VARCHAR(64) NOT NULL,
user_id VARCHAR(64),
response_payload JSONB,
created_at TIMESTAMP,
PRIMARY KEY (user_id, key) — Composite Key untuk uniqueness
);
* Server Logic (Middleware):
// Pseudocode
async function handleRequest(req, res) {
const key = req.headers[‘idempotency-key’];
// 1. Coba insert key (Atomic operation)
try {
await db.insert(‘idempotent_requests’, { key, status: ‘PROCESSING’ });
} catch (error) {
// Jika error ‘Duplicate Entry’, berarti sedang/sudah diproses
const saved = await db.get(key);
return res.send(saved.response_payload);
}
// 2. Proses Bisnis (Bayar, dll)
const result = await processPayment(req.body);
// 3. Update hasil ke tabel log
await db.update(‘idempotent_requests’, { response_payload: result });
return res.send(result);
}
🔗 Baca Artikel Lengkapnya: https://www.morling.dev/blog/on-idempotency-keys/
#SoftwareEngineering #Backend #API #DistributedSystems #DevOps #SystemDesign #Java #Architecture