Idempotency

Idempotency #

Dalam pengembangan web application dan API modern, idempotency adalah salah satu konsep fundamental yang sering diremehkan, tetapi dampaknya sangat besar terhadap reliability, data consistency, dan user experience.

Idempotency menjadi sangat krusial ketika sistem:

  • Berjalan di lingkungan terdistribusi
  • Menghadapi retry otomatis (client, SDK, load balancer)
  • Menggunakan asynchronous processing
  • Berhadapan dengan kegagalan jaringan (network failure)

Artikel ini akan membahas secara mendalam:

  • Apa itu idempotency
  • Masalah nyata yang muncul tanpa idempotency
  • Problem solving yang ditawarkan idempotency
  • Dampaknya pada sistem
  • Best practice implementasi di web application

Apa Itu Idempotency? #

Secara sederhana:

Idempotency adalah sifat sebuah operasi yang jika dijalankan satu kali atau berkali-kali, hasil akhirnya tetap sama.

Dalam konteks web application:

  • Request yang sama dikirim ulang (baik sengaja atau tidak)
  • Sistem tidak menghasilkan efek samping tambahan

Contoh Sederhana #

Operasi:

  • DELETE /users/123

Jika:

  • Request dikirim 1x → user terhapus
  • Request dikirim 5x → user tetap terhapus

➡️ Ini idempotent.

Sebaliknya:

  • POST /payments dengan body yang sama
  • Dipanggil 2x → saldo terpotong 2x

➡️ Ini tidak idempotent.


Idempotency vs HTTP Method #

Secara teori HTTP:

MethodIdempotentAman Digunakan untuk Retry
GET
PUT
DELETE
POST
PATCH❌ (umumnya)

⚠️ Catatan penting: Walaupun GET/PUT/DELETE secara konsep idempotent, implementasi backend-lah yang menentukan apakah benar-benar idempotent atau tidak.


Masalah Nyata Tanpa Idempotency #

Duplicate Transaction #

Kasus klasik:

  • Client mengirim request pembayaran
  • Network timeout terjadi
  • Client melakukan retry
  • Server memproses request dua kali

Akibatnya:

  • Saldo terpotong ganda
  • Order tercatat dobel
  • Masalah finansial & trust user

Inconsistent State #

Tanpa idempotency:

  • Data di database bisa berada di state setengah jalan
  • Side-effect (email, push notification) terkirim berkali-kali

Contoh:

  • Order hanya satu
  • Email konfirmasi terkirim 3x

Retry Storm #

Banyak sistem modern melakukan retry otomatis:

  • Mobile SDK
  • API Gateway
  • Service Mesh
  • Load balancer

Tanpa idempotency:

  • Retry = eksekusi ulang logic bisnis
  • Beban sistem meningkat drastis

Bug yang Sulit Direproduksi #

Bug idempotency biasanya:

  • Tidak muncul di local
  • Tidak muncul di staging
  • Muncul di production saat latency tinggi

➡️ Ini tipe bug paling mahal dan sulit didiagnosa.


Idempotency sebagai Problem Solving #

Idempotency hadir sebagai solusi untuk:

  • Network failure
  • Timeout
  • Duplicate request
  • At-least-once delivery (queue, event-driven)

Dengan idempotency:

  • Request boleh diulang
  • Sistem tetap konsisten
  • Client tidak perlu “takut retry”

Cara Kerja Idempotency (High Level) #

Client
  |
  |--- Request + Idempotency Key --->
  |
Server
  |
  |--- Check idempotency key ---|
  |                              |
  |   Sudah ada? ---- YES -------|--> Return cached result
  |        |
  |        NO
  |        |
  |   Execute business logic
  |        |
  |   Store result + key
  |        |
  |   Return response

Implementasi Idempotency di Web Application #

Idempotency Key #

Pendekatan paling umum:

  • Client mengirim header:

    Idempotency-Key: uuid-v4
    
  • Server:

    • Menyimpan key
    • Mengaitkan key dengan hasil response

Jika key yang sama datang kembali:

  • Logic bisnis tidak dijalankan ulang
  • Response lama dikembalikan

Penyimpanan Idempotency Key #

Umumnya disimpan di:

  • Redis (paling umum)
  • Database

Struktur data:

KeyRequest HashResponseStatusTTL

TTL penting agar:

  • Storage tidak tumbuh tanpa batas
  • Key tidak digunakan selamanya

Request Hashing #

Untuk keamanan:

  • Idempotency key harus konsisten dengan payload

Jika:

  • Key sama
  • Payload berbeda

➡️ Tolak request (400 / 409)

Ini mencegah:

  • Abuse
  • Bug client

Pessimistic Locking dengan Affected Rows (Atomic Claim Pattern) #

Ini adalah pola yang sering dipakai di production, terutama jika tidak ingin distributed lock terpisah (Redis lock, dsb).

Intinya:

  • Gunakan database sebagai single source of truth
  • Manfaatkan atomic update + affected rows untuk “mengklaim” idempotency key

Konsep dasarnya:

  1. Idempotency key disimpan dengan status awal (misalnya: pending)
  2. Request pertama mencoba mengubah status
  3. Hanya satu request yang berhasil mengubah status (affected rows = 1)
  4. Request lain akan mendapat affected rows = 0 → dianggap duplicate

Contoh Skema Tabel #

CREATE TABLE idempotency_keys (
  idempotency_key VARCHAR(64) PRIMARY KEY,
  request_hash VARCHAR(64),
  status VARCHAR(16), -- pending | processing | completed
  response JSON,
  created_at TIMESTAMP
);

Alur Pessimistic Locking (Bagan Text-Based) #

Client 1                     Client 2
   |                             |
   |--- Request(idempotency) --->|
   |                             |
   |                             |
   |--- UPDATE status='processing' affected_rows=1 --->
   |                             |
   |                             |--- UPDATE status='processing' affected_rows=0 ---> duplicate detected
   |                             |
   |--- Execute business logic   |
   |                             |
   |--- UPDATE status='completed' & store response --->
   |                             |
   |<--- Return response --------|
   |                             |
   |                             |<--- Return cached response / error duplicate

Kunci utamanya adalah:

  • UPDATE bersifat atomic
  • Database menjamin hanya satu transaksi yang sukses

Kenapa Ini Disebut Pessimistic? #

Karena:

  • Kita mengasumsikan akan ada race condition
  • Sejak awal, kita mengunci hak eksekusi logic bisnis
  • Request lain langsung dianggap competitor

Berbeda dengan optimistic approach yang berharap conflict jarang terjadi.

Kelebihan Pendekatan Ini #

  • Tidak perlu Redis / distributed lock
  • Konsisten walaupun service restart
  • Cocok untuk sistem finansial
  • Mudah diaudit (berbasis DB)

Kekurangan & Risiko #

  • Bergantung pada performa database
  • Perlu cleanup key lama (TTL via cron)
  • Harus hati-hati dengan transaksi lama (long-running transaction)

Best Practice Penggunaan #

  • Gunakan short transaction

  • Pisahkan:

    • Claim key (DB)
    • Heavy processing (di luar transaksi)
  • Selalu simpan response akhir

  • Kombinasikan dengan unique constraint jika memungkinkan


Database Constraint (Natural Idempotency) #

Alternatif atau pelengkap:

  • Gunakan unique constraint

Contoh:

UNIQUE (order_id, payment_type)

Jika insert kedua terjadi:

  • Database menolak
  • Sistem tetap konsisten

Dampak Positif Idempotency #

Reliability Naik Drastis #

  • Retry aman
  • Failure tidak berdampak fatal

User Experience Lebih Baik #

  • Tidak ada duplicate order
  • Tidak ada double charge

Simplifikasi Client #

  • Client boleh retry tanpa logic kompleks

Observability Lebih Jelas #

  • Duplicate request mudah dilacak

Dampak Negatif Jika Salah Implementasi #

Idempotency yang buruk bisa menyebabkan:

  • Memory leak (TTL tidak diatur)
  • False positive duplicate
  • Deadlock pada concurrent request

➡️ Idempotency harus dirancang, bukan sekadar ditambahkan.


Best Practice Idempotency #

Gunakan untuk Operasi dengan Side Effect #

Fokuskan idempotency pada:

  • Payment
  • Order creation
  • Resource mutation penting

Gunakan TTL yang Masuk Akal #

Contoh:

  • Payment: 24 jam
  • Order creation: 1–6 jam

Locking untuk Concurrent Request #

Jika dua request dengan key sama datang bersamaan:

  • Gunakan distributed lock
  • Pastikan hanya satu eksekusi logic

Kembalikan Response yang Sama #

Untuk key yang sama:

  • Status code
  • Body
  • Header

Harus konsisten.

Jangan Bergantung pada Client Saja #

  • Client bisa buggy
  • Server harus defensive

Kombinasikan dengan Database Constraint #

Idempotency layer ≠ pengganti constraint

Gunakan keduanya.


Kapan Idempotency Wajib? #

Wajib jika:

  • Sistem finansial
  • Distributed system
  • Mobile application
  • Event-driven architecture

Opsional (tapi tetap disarankan):

  • CRUD sederhana

Penutup #

Idempotency bukan sekadar “nice to have” — ia adalah pondasi keandalan sistem modern.

Banyak bug mahal di production bukan karena logic bisnis salah, tetapi karena:

Sistem tidak siap menghadapi retry.

Dengan idempotency yang baik:

  • Sistem lebih tahan banting
  • Data lebih konsisten
  • Tim lebih tenang saat incident

Jika Anda membangun web application serius, anggap idempotency sebagai default mindset, bukan fitur tambahan.

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact