Güvenli tekrar deneme için API'de idempotency anahtarı uygulaması
Beceri rehberi

Güvenli tekrar deneme için API'de idempotency anahtarı uygulaması

Hazırlayan: Mindset Institute EditörlüğüGüncellendi: 5 dk okuma

Tekrarlanan istekler çift işlem yaratmasın: idempotency anahtarı akışı, veritabanı şeması, dış sistemler, mesaj tekilleştirme ve sık hatalar.

Tekrar problemi: istek gitti mi, gitmedi mi?

Bir istemci ödeme isteği gönderir, yanıt gelmeden bağlantı zaman aşımına uğrar. İstemci isteğin işlenip işlenmediğini bilemez. Sunucu işlemi tamamlamış olabilir, hiç almamış olabilir ya da yarıda kalmış olabilir. Güvenli bir tekrar deneme mekanizması yoksa istemcinin önünde kötü seçenekler kalır: denemezse işlem kaybolabilir, denerse işlem çift uygulanabilir.

Aynı sorun yalnızca mobil istemcilerde olmaz. Yük dengeleyici tarafından yeniden denenen istekler, mesaj kuyruğunun "en az bir kez teslim" güvencesi, kullanıcının düğmeye arka arkaya basması ve servisler arası otomatik retry politikaları da aynı isteği birden fazla kez sunucuya ulaştırır. Dağıtık sistemlerde tekrar kural dışı değil, beklenen davranıştır.

Çözüm, tekrarı engellemek değil, tekrarı zararsız hale getirmektir. İşte idempotency (tekrar güvenliği) tam olarak budur: aynı isteğin birden fazla kez uygulanması, bir kez uygulanmasıyla aynı sonucu bırakır. Kavramın kendisi sözlük düzeyinde basittir; zor olan, bunu bir API'de gerçekten sağlamaktır.

Hangi istekler doğal olarak idempotent, hangileri değil?

HTTP anlam kurallarına göre okuma (GET), tam kaynak değiştirme (PUT) ve silme (DELETE) yöntemleri idempotent kabul edilir. "Bu kaynağı şu hale getir" türü komutlar, tekrar çalıştığında durumu değiştirmez. Buna karşılık POST ile yeni kayıt oluşturmak ya da "bakiyeyi artır" gibi göreli bir değişiklik yapmak doğal olarak idempotent değildir. Her tekrar yeni bir sipariş, yeni bir tahsilat ya da ek bir artış üretir.

Pratik kural: yan etkisi olan her işlem için kendinize şu soruyu sorun. Bu istek aynı gövdeyle tekrar gelirse ne olur? Sonuç ikinci bir kayıtsa, ikinci bir e-postaysa, ikinci bir para hareketiyse o uç nokta tekrar güvenliği tasarımı gerektirir. Hesap bakiyesi gibi durumu doğrudan "ayarlayan" işlemlerde veya sürüm numarasıyla korunan güncellemelerde (koşullu güncelleme) sorun daha küçüktür; asıl risk, yeni nesne yaratan ve dış sisteme dokunan işlemlerdedir.

Idempotency anahtarı yaklaşımı: akış nasıl işler?

En yaygın yöntem, istemcinin her mantıksal işlem için benzersiz bir anahtar üretip isteğin başlığında göndermesidir. Bu amaçla Idempotency-Key başlığı kullanılır; bu başlığı standartlaştırmayı amaçlayan bir IETF taslağı vardır, ancak taslağın süresi dolmuştur ve henüz RFC değildir. Bu nedenle başlığın adını ve davranışını kendi API sözleşmenizde açıkça tanımlamalısınız.

Örnek istek (adlar kurguseldir):

POST /odemeler Idempotency-Key: <istemcinin ürettiği benzersiz değer> Content-Type: application/json

Sunucu tarafında akış şöyledir: • Anahtar daha önce hiç görülmediyse işlem "devam ediyor" kaydıyla başlatılır • İşlem bittiğinde sonuç (durum kodu ve yanıt gövdesi) anahtarla birlikte saklanır • Aynı anahtar aynı içerikle yeniden gelirse sunucu işlemi tekrar çalıştırmaz, saklanan yanıtı aynen döner • Aynı anahtar farklı bir gövdeyle gelirse bu bir istemci hatasıdır; istek reddedilir • Aynı anahtar işlem hâlâ sürerken tekrar gelirse çakışma durumu bildirilir, istemci kısa süre sonra yeniden dener

Anahtar, istemci tarafından üretilmelidir; çünkü sunucu yalnızca kendi görmediği bir isteği tanımlamak için anahtar üretemez. Yeterince rastgele, tahmin edilmesi zor değerler (örneğin UUID) tercih edilir ve anahtar, aynı müşteri kapsamında benzersiz sayılır.

Veritabanında nasıl uygulanır? Küçük bir şema örneği

Anahtarın tekilliğini uygulama koduna bırakmak yarış durumuna açık kalır. Güvenceyi veritabanının benzersizlik kısıtı sağlamalıdır. Örnek bir tablo (PostgreSQL biçimi):

CREATE TABLE idempotency_keys ( client_id text NOT NULL, key text NOT NULL, request_hash text NOT NULL, status text NOT NULL, response_body jsonb, created_at timestamptz NOT NULL DEFAULT now(), PRIMARY KEY (client_id, key) );

İstek geldiğinde önce anahtarı eklemeyi deneyin:

INSERT INTO idempotency_keys (client_id, key, request_hash, status) VALUES (:client_id, :key, :request_hash, 'in_progress') ON CONFLICT (client_id, key) DO NOTHING;

Ekleme gerçekleştiyse siz kazandınız: işlemi yürütebilirsiniz. Gerçekleşmediyse kayıt zaten var; durumuna bakın. Tamamlanmışsa saklanan yanıtı döndürün, devam ediyorsa çakışma bildirin, request_hash farklıysa isteği reddedin. request_hash, istek gövdesinin özetidir ve aynı anahtarın başka bir istek için yanlışlıkla kullanılmasını yakalar.

Kritik nokta: anahtar kaydını ve işin kendisini mümkünse aynı veritabanı işleminde (transaction) yapın. Aksi halde iş yapılır ama anahtar kaydedilmez ya da tersi olur ve bir sonraki tekrar yine çift işlem üretir.

Dış sistemler, mesajlaşma ve zaman aşımı

Kendi veritabanınızın dışına yan etki taşıyorsanız (ödeme sağlayıcısı, e-posta servisi, kargo entegrasyonu) tek başına anahtar tablosu yetmez. İşlemi dış servise iletirken aynı anahtarı ona da geçirin; birçok ödeme ve mesajlaşma servisi bunu destekler. Dış servis desteklemiyorsa, çağrıdan önce niyeti (örneğin "gönderilecek") kaydedip sonucu sonra işleyen bir mutabakat adımı kurmak gerekir.

Mesaj tüketicilerinde de aynı mantık geçerlidir. Kuyruk sistemleri çoğu zaman "en az bir kez" teslim eder, yani aynı mesaj birden fazla gelebilir. Tüketici, işlediği mesaj kimliklerini saklayıp daha önce işlenmiş olanları atlayarak tekilleştirme yapar. Veritabanı değişikliği ile mesaj yayınlamayı birbirinden güvenle ayırmak için outbox deseni kullanılır: mesaj önce aynı işlemde bir tabloya yazılır, ayrı bir süreç oradan yayınlar.

Saklanan anahtarlar sonsuza kadar tutulmaz. Makul bir saklama süresi belirleyin ve süre bitiminde kayıtları temizleyin. İstemciye de tekrar denemeyi hemen ve sınırsız yapmamasını, artan bekleme süresi ve rastgele sapma (jitter) ile denemesini önerin.

Sık yapılan hatalar ve test yaklaşımı

Gerçek sistemlerde en sık karşılaşılan hatalar şunlardır: • Anahtarı sunucuda üretmek; istemci timeout sonrası aynı anahtarı bilemez • Anahtarı yalnızca bellekte (örneğin tek sunucunun önbelleğinde) tutmak; yük dengeleyici başka sunucuya yönlendirince tekrar yakalanmaz • Gövde özetini kontrol etmemek; farklı bir istek, eski bir anahtarla geçmiş sayılır • Yalnızca başarılı yanıtları saklamak; hata dönen işlemin tekrarında farklı davranış çıkabilir, bu da istemciyi şaşırtır • Anahtar kapsamını müşteri bazında ayırmamak; bir müşterinin anahtarı başka birinin işlemiyle çakışabilir

Testte aynı isteği art arda ve eşzamanlı göndermeyi deneyin. Beklenen sonuç: tek kayıt, tekrar edilen isteklerde aynı yanıt, farklı gövdede ret. Ağ hatası simülasyonuyla yanıtın istemciye ulaşmadığı durumu da çalıştırın; asıl sorun orada ortaya çıkar. Son olarak operasyon tarafını unutmayın: bekleyen "devam ediyor" kayıtlarının zaman aşımına uğradığı ve temizlendiği bir süreç tanımlayın, aksi halde çöken bir işlem anahtarı sonsuza dek kilitli bırakır.

Bu beceriyi Mindset programlarında nerede çalışırsınız?

Bu konu, ödeme, sipariş ve entegrasyon API'leri geliştiren arka uç ekiplerine, mikro hizmet mimarisine geçen ekiplere ve güvenilirlik mühendislerine yöneliktir. Ortak sorun, ağ ve kuyruk kaynaklı tekrarların veri tutarlılığını sessizce bozmasıdır.

Idempotency ve Dağıtık Tutarlılık Desenleri eğitiminin modül başlıkları bu sorunu katman katman ele alır: tekrar problemi ve idempotency temelleri, anahtar tasarımı, veritabanı seviyesinde tutarlılık, mesajlaşmada tekilleştirme, outbox ve değişiklik verisi yakalama, mutabakat, test ve operasyon. Ekipler kendi ödeme ya da sipariş akışlarını bu sırayla gözden geçirebilir.

İlgili Mindset programı

Idempotency ve Dağıtık Tutarlılık Desenleri

Sık sorulanlar

Sık sorulan sorular

Idempotency anahtarı ile veritabanı benzersiz kısıtı aynı şey midir?

Hayır, birbirini tamamlarlar. Anahtar, istemcinin bir mantıksal işlemi tanımlama yoludur; benzersiz kısıt ise o anahtarın eşzamanlı isteklerde bile yalnızca bir kez kabul edilmesini sağlayan veritabanı güvencesidir. Anahtarın kendisi uygulamada üretilir, güvence ise kısıtla kurulur. Biri olmadan diğeri tam koruma vermez.

Her API uç noktasına idempotency anahtarı eklemek gerekir mi?

Gerekmez. Okuma ve doğal olarak idempotent olan güncellemeler ek mekanizma istemez. Anahtar, yeni nesne oluşturan ya da geri alınması zor yan etkisi olan işlemlerde (ödeme, sipariş, bildirim gönderimi, para transferi) değer üretir. Gereksiz yere her uç noktaya eklemek saklama ve karmaşıklık maliyeti getirir.

İstemci aynı anahtarla farklı bir gövde gönderirse sunucu ne yapmalı?

İsteği reddetmelidir. Bu durum genellikle istemci hatasının işaretidir; anahtar yanlışlıkla yeniden kullanılmış ya da bir hata nedeniyle gövde değişmiştir. Sessizce eski yanıtı vermek yanlış sonucun gizlenmesine, yeni isteği işlemek ise mükerrer kayda yol açar. Net bir hata mesajı, sorunun erken fark edilmesini sağlar.

Retry ve idempotency birlikte nasıl düşünülmeli?

Retry, hata anında isteği yeniden göndermektir; idempotency ise bunun güvenli olmasını sağlar. Idempotency olmadan retry politikasını açmak çift işlem riski yaratır. Servis ağı ya da istemci kütüphanesi otomatik tekrar deniyorsa, o rotanın ucundaki işlemin idempotent olduğundan emin olun; aksi halde yeniden denemeyi yalnızca güvenli yöntemlerle sınırlayın.

API'de Idempotency Nasıl Sağlanır? Anahtar Tasarımı