7 dk okuma
Giriş
Mikroservis mimarilerinde aynı isteğin birden fazla kez sisteme ulaşması istisna değil, normal bir durumdur. Ağ yeniden denemeleri, istemci tarafı tekrar gönderimler, zaman aşımı senaryoları, yük dengeleme davranışları veya mesajlaşma altyapıları aynı komutun birden fazla kez işlenmesine neden olabilir. Bu durum ödeme alma, sipariş oluşturma, stok düşme veya dış sistem çağrıları gibi kritik işlemlerde çift kayıt, çift tahsilat ya da veri tutarsızlığı üretir.
İdempotent API tasarımı, aynı isteğin birden fazla kez gönderilmesi halinde sistemin tek bir işlem etkisi üretmesini ve tekrar eden çağrılarda tutarlı yanıt döndürmesini hedefler. Konu yalnızca teorik bir HTTP ilkesi değildir; veri modeli, transaction yönetimi, hata ele alma, gözlemlenebilirlik ve test stratejisiyle birlikte düşünülmesi gereken uygulamalı bir mimari karar alanıdır.
Bu yazıda idempotensi kavramını mikroservis bakış açısıyla ele alacak, neden önemli olduğunu açıklayacak, idempotency-key yaklaşımını inceleyecek ve .NET 8 ile uygulanabilir bir çözüm taslağı paylaşacağız.
İdempotensi Anlamak
Bir işlemin idempotent olması, aynı istek birden fazla kez işlense bile sistemin gözlemlenebilir sonucunun değişmemesi anlamına gelir. HTTP düzeyinde GET, PUT veya DELETE gibi metodlar teoride idempotent kabul edilse de pratikte iş kuralı seviyesinde bu her zaman otomatik olarak sağlanmaz.
Örneğin “sipariş oluştur” veya “ödeme başlat” gibi POST tabanlı komutlar doğal olarak idempotent değildir. İstemci aynı isteği iki kez gönderirse iki farklı sipariş veya iki farklı ödeme kaydı oluşabilir. Bu yüzden idempotensi sadece metod seçimiyle değil, işleme ait benzersiz bir anahtar, kayıt mekanizması ve tekrar işleme politikasıyla kurmak gerekir.
Neden Kritik?
Dağıtık sistemlerde yüzde yüz güvenilir ağ varsayımı yapmak mümkün değildir. İstemci bir yanıtı geç aldıysa isteğin başarısız mı yoksa gecikmeli mi olduğunu anlayamayabilir ve aynı isteği tekrar gönderebilir. Gateway veya reverse proxy katmanları da timeout sonrası yeni bir deneme yapabilir.
İdempotensi sağlamak; finansal doğruluk, sipariş bütünlüğü, entegrasyon güvenilirliği ve kullanıcı deneyimi açısından kritiktir. Kullanıcı aynı butona iki kez bastığında sistemin iki ayrı işlem üretmemesi beklenir. Benzer şekilde webhook, event consumer veya queue consumer tasarımlarında en az bir kez teslimat modelini güvenli hale getirmek için de idempotent yaklaşım gerekir.
Temel Tasarım Prensipleri
İdempotent tasarımın ilk prensibi istek kimliğinin benzersiz ve tahmin edilemez olmasıdır. Bu anahtar genellikle istemci tarafından üretilen bir Idempotency-Key değeridir.
İkinci prensip, anahtarın uygun kapsamla saklanmasıdır. Aynı anahtar tüm sistemde mi, belirli bir kullanıcı için mi yoksa belirli bir endpoint için mi benzersiz olacak sorusu netleştirilmelidir.
Üçüncü prensip, ilk işleme sonucu ile tekrar eden istekler arasında tutarlı davranış sağlamaktır. Yani ilk istek başarıyla sonuçlandıysa sonraki tekrarlar aynı sonucu döndürmeli; işlem devam ediyorsa uygun durum kodu ve anlamlı mesajlar verilmelidir.
Dördüncü prensip ise atomikliktir. Anahtar kaydı ile iş kuralı sonucu arasındaki ilişki yarım kalmayacak şekilde tasarlanmalıdır. Aksi halde anahtar kaydolur ama işlem tamamlanmazsa sistem çelişkili hale gelir.
Idempotency-Key Kullanımı
Yaygın yaklaşım, istemcinin her kritik POST isteğinde benzersiz bir Idempotency-Key göndermesidir. Sunucu isteği aldığında önce bu anahtarı ve isteğin bağlamını kontrol eder.
Anahtar daha önce görülmemişse işlem normal şekilde yürütülür, ardından işlem sonucu ve gerekiyorsa response özeti birlikte saklanır. Aynı anahtarla gelen yeni bir istek görüldüğünde sistem iş kuralını yeniden çalıştırmak yerine önceki sonucu döndürür.
Burada request hash kullanımı da değerlidir. Çünkü aynı anahtarın farklı payload ile kullanılmasını engellemek gerekir. Anahtar ile birlikte istek özeti saklanırsa, farklı payload ile gelen çakışmalar güvenli biçimde reddedilebilir.
.NET 8 ile Uygulama Yaklaşımı
.NET 8 tarafında bu desen, middleware, action filter veya endpoint filter olarak uygulanabilir. Minimal API ya da controller tabanlı yapılarda isteğin başında Idempotency-Key okunur ve bir servis katmanına devredilir.
Tipik akış şöyledir: header doğrulanır, kapsam anahtarı üretilir, depoda mevcut kayıt aranır, kayıt yoksa işlem transaction içinde yürütülür, sonuç saklanır ve istemciye döndürülür. Kayıt varsa response yeniden üretilir veya saklanan response geri verilir.
Özellikle ödeme, sipariş ve dış sistem entegrasyonları için ortak bir IdempotencyService soyutlaması kurmak, bu davranışı endpoint bazında tekrar tekrar kodlamak yerine merkezi ve test edilebilir hale getirir.
Depolama Seçenekleri: SQL Server ve Redis
SQL Server kullanımı güçlü tutarlılık gerektiren senaryolarda avantajlıdır. Idempotency kaydı için benzersiz indeks içeren bir tablo oluşturulabilir. Böylece paralel isteklerde aynı anahtar yalnızca bir kez yazılabilir. İşlem sonucu, durum bilgisi, oluşturulma zamanı ve TTL alanı tutulabilir.
Redis ise çok hızlı erişim ve TTL yönetimi sağladığı için hafif senaryolarda öne çıkar. Ancak kritik finansal işlemlerde yalnızca cache mantığıyla değil, dayanıklılık ve restart davranışları da düşünülerek kullanılmalıdır. Pek çok sistemde hibrit yaklaşım seçilir: kaynak doğruluk SQL Server’da, kısa ömürlü hız optimizasyonu Redis’te tutulur.
Test ve Doğrulama
İdempotent API geliştirmek kadar bunu kanıtlamak da önemlidir. Birim testlerde aynı anahtar ile ardışık tekrarlar kontrol edilmeli, entegrasyon testlerinde paralel istek senaryoları simüle edilmelidir.
Yük testlerinde aynı payload ve aynı anahtar ile yüzlerce veya binlerce tekrar göndererek tek işlem etkisi, tek kayıt üretimi ve tutarlı response davranışı doğrulanmalıdır. Ayrıca timeout sonrası yeniden deneme, yarım kalan işlem, veri tabanı hatası ve race condition senaryoları da kapsanmalıdır.
En İyi Uygulamalar
Idempotency-Key için TTL stratejisi belirleyin. Her isteği sonsuza kadar saklamak maliyetli olabilir; iş senaryosuna göre saatlik veya günlük pencere seçin.
Anahtarı kullanıcı, tenant, endpoint veya komut tipi ile birlikte isimlendirin. Böylece yanlış kapsam yüzünden farklı işlemler birbirini etkilemez.
İlk response gövdesi tekrar kullanılacaksa serializasyon biçimini standartlaştırın. Response’un aynısını döndürmek istemiyorsanız tutarlı bir çıktı sözleşmesi tanımlayın.
Log ve metrik ekleyin: idempotency hit/miss oranı, çakışma sayısı, TTL temizleme başarısı ve hata oranları production takibinde çok değerlidir.
Sadece teknik olarak değil, iş kuralı açısından da idempotent davranışı dokümante edin. API tüketen ekipler hangi endpoint’lerde anahtar göndermek zorunda olduklarını açık biçimde bilmelidir.
Sonuç
İdempotent API tasarımı, mikroservislerde güvenilirliği artıran temel desenlerden biridir. Aynı isteğin tekrar gelmesi halinde sistemin çift işlem üretmemesi; hem veri doğruluğu hem de kullanıcı güveni için kritik önemdedir.
Doğru kapsamlandırılmış anahtar, atomik kayıt mantığı, uygun depolama tercihi, gözlemlenebilirlik ve stres testleri ile desteklenen bir idempotensi yaklaşımı; .NET 8 tabanlı servislerde üretim kalitesini belirgin biçimde yükseltir. Özellikle ödeme, sipariş, bildirim ve entegrasyon akışlarında bu yaklaşımın standart hale getirilmesi uzun vadede önemli operasyonel fayda üretir.
Araştırma Kaynakları ve İleri Okuma
Microsoft Learn – API design best practices: https://learn.microsoft.com/azure/architecture/best-practices/api-design
AWS Builders’ Library – Making retries safe with idempotent APIs: https://aws.amazon.com/builders-library/making-retries-safe-with-idempotent-APIs/
Stripe API Docs – Idempotent requests: https://stripe.com/docs/api/idempotent_requests
Martin Fowler – Idempotent Receiver: https://martinfowler.com/articles/patterns-of-distributed-systems/idempotent-receiver.html

