Oyun Kitabı
Webhook Altında Optimistic Concurrency (Webhook Altinda Optimistic Concurrency)
Webhook ile senkron yanıt aynı ödemeye aynı anda dokunduğunda version token ve lease nasıl yarışı çözer? Bayat okumanın terminal ödemede client secret…
Dağıtık Ödeme Motoru (Distributed Payment Engine)
Bolum 17 / 22
Capture ile complete arasındaki boşluğu kapatan dağıtık ödeme mimarisi serisi.
Önceki bölümde eventual consistency'nin neden kaçınılmaz olduğunu gördük: PSP transaction protokolünüze katılamaz, saga ve mutabakat gerçek cevaptır. Bu bölüm, o tutarsızlık penceresinin en yoğun anına odaklanıyor — webhook ile senkron yanıtın aynı ödeme kaydına eşzamanlı dokunduğu an.
Checkout orchestrator bir charge isteği gönderir; provider gateway PSP'den yanıt alır. Aynı anda — bazen milisaniyeler önce, bazen sonra — aynı ödeme için bir webhook gelir. İki yol da doğru bilgi taşıyabilir; ikisi de aynı anda yazmaya kalkarsa sonuç ya kayıp güncelleme ya da daha kötüsü, terminal bir ödemede bayat okumaya dayalı yanlış bir client yanıtıdır.
Senkron yanıt ──► Payment #42 (version=3) ──► Captured
Webhook ──► Payment #42 (version=3) ──► Captured (tekrar?)
│
▼
Version token + lease
→ tek kazanan yazar
Optimistic concurrency burada bir performans optimizasyonu değil; terminal statüde yanlış veri döndürmemenin mekanizmasıdır.
Kavramlar ilk geçtiği yerde
📦 Version Token (Optimistic Lock)
Her güncellemede artan sayaç; yazma yalnızca beklenen sürüm eşleşirse başarılı olur.
📦 Lease
Bir worker'ın belirli bir ödeme kaydını işleme hakkını süre sınırlı olarak alması.
📦 Stale Read
İşlem sırasında okunan ama yazma anında artık geçerli olmayan eski sürüm.
📦 Terminal Payment
Captured, Failed veya Refunded gibi geri dönüşü olmayan nihai statü.
Lease, bir worker'ın 'bu kaydı ben işliyorum' demesidir; version token ise 'ben hâlâ bu sürümü görüyorum' demesidir. İkisi birlikte, webhook ile senkron yolun birbirinin üzerine yazmasını engeller.
İki yol, tek kayıt: yarış nerede başlar
Bir redirect tabanlı ödemede senkron yol genellikle Pending döner; gerçek sonuç webhook ile gelir. Kart ödemesinde ise her iki yol da Captured veya Failed taşıyabilir — ve ikisi de neredeyse aynı anda ulaşabilir. Checkout orchestrator her iki yoldan gelen bilgiyi aynı payment satırına yazmaya çalışır.
Klasik hata: her iki handler da kaydı okur, statüyü günceller, kaydeder. Son yazan kazanır; aradaki güncelleme sessizce kaybolur. Daha tehlikeli senaryo: orchestrator terminal statüye geçmeden önce eski bir sürümü okur ve müşteriye hâlá geçerli görünen bir client secret veya redirect URL döner — ödeme aslında çoktan tamamlanmış veya başarısız olmuştur.
T=0 Orchestrator: charge gönder
T=1 Webhook gelir → Captured yaz (version 2→3)
T=2 Senkron yanıt gelir → Pending okudu (version 1)
→ client'a redirectUrl döner (bayat!)
T=3 Müşteri redirect'e gider → ödeme zaten Captured
Version token: yazma ancak sürüm eşleşirse
Her payment kaydında monoton artan bir version alanı tutulur. Güncelleme şu koşulla yapılır: UPDATE ... WHERE id = ? AND version = ?. Eşleşme yoksa güncelleme sıfır satır etkiler — bu, başka bir yolun araya girdiğinin sinyalidir.
Webhook handler
READ payment (version=2, status=Processing)
→ status=Captured, version=3
UPDATE WHERE version=2 ✓ (1 row)
Senkron handler (bayat okuma)
READ payment (version=2, status=Processing) ← webhook henüz commit olmadı
→ status=Captured, version=3
UPDATE WHERE version=2 ✗ (0 rows — webhook zaten yazdı)
→ yeniden oku, terminal statüyü gör, client secret döndürme
Version token tek başına yeterli değildir; stale read'i tespit ettikten sonra ne yapılacağını da tanımlamak gerekir: yeniden oku, terminal statüyü kontrol et, client'a yalnızca güncel durumu döndür.
Lease: webhook işleme hakkını süre sınırlı almak
Webhook handler'ı kayda dokunmadan önce kısa süreli bir lease alır: 'Payment #42'yi 30 saniye boyunca ben işliyorum.' Lease süresi boyunca başka bir worker aynı kaydı webhook veya recovery akışında işleyemez.
Webhook gelir
→ lease al (paymentId, ttl=30s)
→ lease alınamazsa → defer / retry
→ lease alındı → version token ile güncelle
→ lease bırak
Lease, aynı webhook'un iki worker tarafından eşzamanlı işlenmesini engeller. Version token ise farklı yolların (senkron vs webhook) çakışmasını çözer. İkisi farklı sorunlara cevap verir; birlikte kullanılmaları gerekir.
Terminal ödemede client secret sızıntısı
En ciddi stale-read senaryosu terminal statüde client secret veya redirect URL dönmektir. Ödeme Captured olduktan sonra müşteriye hâlâ Pending + redirectUrl dönmek, gereksiz bir ikinci charge denemesine veya kafa karışıklığına yol açar.
Kural basittir: terminal statüye geçmiş bir ödemede client secret, redirect URL veya yeniden deneme token'ı asla döndürülmez. Handler, version conflict aldığında veya stale read şüphesi varsa kaydı yeniden okur; terminal statü görürse yalnızca nihai sonucu döner.
| Durum | Client'a dönen |
|---|---|
| Processing, redirect gerekli | redirectUrl (geçerli) |
| Captured (terminal) | Başarı sonucu, secret yok |
| Failed (terminal) | Hata sonucu, secret yok |
| Version conflict → yeniden oku → Captured | Başarı sonucu, secret yok |
Sık karıştırılan ayrımlar
❌ Pessimistic lock her zaman daha güvenlidir
✓ Ödeme akışında kısa süreli lease + version token, throughput'u korurken yarışı çözer
❌ Version conflict = hata, exception fırlat
✓ Version conflict = başka yol kazandı; yeniden oku ve güncel duruma uy
❌ Lease ve version token aynı şeyi yapar
✓ Lease aynı kaydın eşzamanlı işlenmesini engeller; version token eşzamanlı yazmayı
Lease vs version token
| Kriter | Lease | Version Token |
|---|---|---|
| Engellediği | Aynı kaydın paralel işlenmesi | Kayıp güncelleme (lost update) |
| Süresi | TTL ile sınırlı | Kalıcı, her yazmada artar |
| Conflict davranışı | Bekle / defer | Yeniden oku / retry |
Optimistic concurrency kontrol listesi
- Payment güncellemeleri
WHERE version = ?koşuluyla mı yapılıyor? - Version conflict alındığında handler yeniden okuyup terminal statüyü kontrol ediyor mu?
- Terminal statüde client secret veya redirect URL dönülmesi kod seviyesinde engellenmiş mi?
- Webhook handler'ı işleme başlamadan lease alıyor mu?
- Lease süresi, webhook işleme süresinin P99'undan uzun mu?
- Senkron yanıt handler'ı ile webhook handler'ı aynı finalize mantığını mı paylaşıyor?
Bu yazıdan aklında ne kalmalı
- Webhook ile senkron yol aynı kayda eşzamanlı dokunur; optimistic concurrency bu yarışın standart cevabıdır.
- Version token kayıp güncellemeyi engeller; lease aynı kaydın paralel işlenmesini engeller.
- Version conflict bir hata değil, yeniden okuma sinyalidir.
- Terminal ödemede bayat okumadan client secret dönmek, sessiz bir güvenlik ve UX hatasıdır.
Yarışı çözmek için pessimistic lock'a ihtiyacınız yok; ihtiyacınız olan, bayat okumanın client'a ulaşmasını engelleyen disiplinli bir version token ve lease kombinasyonudur.
Bir sonraki bölümde bu yarışları ve finalize adımlarını görebilmek için observability'ye geçiyoruz: payment id ile korelasyon, adım adım event log ve deferred finalize metrikleri.
SSS
Sık sorulan sorular
Version Token (Optimistic Lock) nedir?
Her güncellemede artan sayaç; yazma yalnızca beklenen sürüm eşleşirse başarılı olur.
Lease nedir?
Bir worker'ın belirli bir ödeme kaydını işleme hakkını süre sınırlı olarak alması.
"Pessimistic lock her zaman daha güvenlidir" doğru mu?
Ödeme akışında kısa süreli lease + version token, throughput'u korurken yarışı çözer
Bu bölüm neyi sabitler?
Optimistic concurrency burada bir performans optimizasyonu değil; terminal statüde yanlış veri döndürmemenin mekanizmasıdır. Webhook ile senkron yol aynı kayda eşzamanlı dokunur; optimistic concurrency bu yarışın standart cevabıdır. Önceki bölümde eventual consistency'nin neden kaçınılmaz olduğunu gördük: PSP transaction protokolünüze katılamaz, saga ve mutabakat gerçek cevaptır. Bu bölüm, o tutarsızlık penceresinin en yoğun anına odaklanıyor — webhook ile senkron yanıtın aynı ödeme kaydına eşzamanlı dokunduğu an.
Ogrenilen Muhendislik Prensipleri
- Version token kayıp güncellemeyi engeller; conflict yeniden okuma sinyalidir.
- Lease ile version token farklı yarışları çözer; ikisi birlikte kullanılmalıdır.
- Terminal ödemede bayat okumadan client secret dönülmemelidir.
Okumaya devam et
Okumaya devam et
Seride sonraki yazi
Ödeme Gözlemlenebilirlik ve Korelasyon
Her log, metrik ve trace payment id ile nasıl korele edilir? Adım adım event log ve deferred finalize metrikleri operasyonu nasıl kurtarır?
Seride sonraki yazi
Neden Eventual Consistency Dağıtık Transaction'dan Üstün
PSP, sipariş ve finans arasında 2PC kurmak bir tuzaktır. Saga ve mutabakat, dağıtık ödeme tutarlılığının gerçek cevabıdır.
Ayni seriden
Ödeme Kurtarma Pipeline ve Runbook
Otomasyon önce: reconciliation worker ve recovery pipeline. Uniqueness duvarları replay'i engellediğinde kanıta dayalı insan runbook'ları devreye girer.