← Blog

Aynı istek iki kez gelir: idempotency

28 Eylül 2026·2 dakikayazılımmimariAPI

Dağıtık bir sistemde ağ, bir isteğin karşıya ulaşıp ulaşmadığını her zaman söylemez. İstemci zaman aşımı alır ve tekrar dener; oysa ilk istek sunucuda çoktan işlenmiş olabilir. Bir satış kaydında, bir ödemede ya da bir stok düşümünde bu, aynı işlemin iki kez yazılması demektir.

Idempotency, aynı isteğin bir kez de gelse on kez de gelse sistemi aynı son duruma getirmesidir.

Nerede ortaya çıkar?

  • POS ve kasa: mağazada internet kesilir, kasa satışı tekrar gönderir.
  • Mobil uygulama: kullanıcı "öde" butonuna iki kez basar.
  • Ödeme sağlayıcı bildirimleri (webhook): aynı bildirim birden fazla kez gönderilir.
  • Zamanlanmış görevler: gece çalışan bir görev yeniden başlatılır ve aynı günü tekrar işler.

Idempotency anahtarı

En yaygın çözüm, istemcinin her işlem için benzersiz bir anahtar üretip isteğe eklemesidir. Sunucu anahtarı ilk kez görüyorsa işlemi yapar ve sonucu anahtarla birlikte saklar; aynı anahtarla gelen sonraki isteklere kaydedilmiş sonucu döner.

async function satisOlustur(req: Request) {
  const key = req.headers.get("Idempotency-Key");
  if (!key) return hata(400, "IDEMPOTENCY_KEY_GEREKLI");

  const onceki = await db.idempotency.find(key);
  if (onceki) return onceki.yanit;          // tekrar: aynı sonucu dön

  const yanit = await db.transaction(async (tx) => {
    const satis = await tx.satis.create(/* … */);
    await tx.idempotency.create({ key, yanit: satis });
    return satis;
  });
  return yanit;
}

Anahtar kaydı ile işlemin kendisi aynı veritabanı işleminde (transaction) yazılmalıdır. Aksi hâlde işlem yazılıp anahtar yazılamadığında, tekrar gelen istek işlemi ikinci kez yapar.

Veritabanı kısıtları son savunma hattıdır

Uygulama kodundaki kontrol, iki isteğin aynı anda gelmesi durumunda yetersiz kalabilir. İş kuralını bir benzersizlik kısıtı ile veritabanına da yazmak, yarış durumlarını kesin olarak kapatır: aynı anahtara sahip ikinci kayıt, kod ne derse desin reddedilir.

Zamanlanmış görevlerde

Bu sitenin arkasındaki kişisel panelde, kart taksitlerini hesap kesim gününde otomatik yazan bir görev var. Görevin aynı gün iki kez çalışması hâlinde taksitin iki kez yazılmaması için her kaydın, kart ve kesim tarihinden üretilen bir anahtarı var. Görev ne kadar çalışırsa çalışsın sonuç aynı kalıyor. Panelin geri kalanını bu yazıda anlattım.

Idempotency'yi bir kütüphane özelliği değil, bir sözleşme olarak düşünün: hangi uç noktaların tekrar güvenli olduğunu, anahtarın ne kadar süre saklanacağını ve çakışmada hangi hata kodunun döneceğini API belgesine yazın.

Hata kodları da tutarlı olmalı

Tekrar gelen isteğe ilk sonucun aynısını dönmek kadar, farklı içerikle aynı anahtarın kullanıldığı durumu yakalamak da önemlidir. Bu durumda işlemi yapmak yerine açık bir hata kodu dönmek, istemcideki hatayı görünür kılar. Tüm servislerde tek şemalı bir hata formatı kullanmak, istemcilerin bu durumları tek bir yerde ele almasını sağlar.