Oyun Kitabı
Ödemelerde Effectively-Once İşleme (Odemelerde Effectively Once İsleme)
Exactly-once messaging bir yalandır. Defense in depth ile idempotency, dedup, outbox ve reconciliation birleşince effectively-once iş sonucu nasıl elde edilir?
Dağıtık Ödeme Motoru (Distributed Payment Engine)
Bolum 20 / 22
Capture ile complete arasındaki boşluğu kapatan dağıtık ödeme mimarisi serisi.
Önceki bölümde recovery pipeline'ın otomasyon önce prensibiyle çalıştığını ve uniqueness duvarlarında kanıta dayalı runbook'ların devreye girdiğini gördük. Bu bölüm, pipeline'ın üzerinde yatan messaging garantilerine iniyor — ve endüstrinin en yaygın yanılgısına: exactly-once delivery.
Broker satıcıları 'exactly-once semantics' vaat eder. Gerçek şu: dağıtık bir sistemde bir mesajın tam olarak bir kez işlenmesi fiziksel olarak garanti edilemez. Ağ kopar, worker çöker, broker yeniden gönderir. Soru 'mesaj kaç kez geldi' değil; iş sonucu kaç kez gerçekleşti.
Exactly-once messaging → imkansız (at-least-once + failure = duplicate)
Effectively-once outcome → mümkün (defense in depth)
Kavramlar ilk geçtiği yerde
📦 At-Least-Once Delivery
Mesaj en az bir kez ulaşır; ağ hatasında tekrar gönderilebilir.
📦 Effectively-Once
Mesaj birden fazla kez işlense bile iş sonucu (charge, refund, order) yalnızca bir kez gerçekleşir.
📦 Defense in Depth
Tek bir mekanizmaya güvenmek yerine, birden fazla bağımsız koruma katmanı.
📦 Idempotent Consumer
Aynı mesajı ikinci kez aldığında aynı sonucu üreten, yan etki yaratmayan tüketici.
Exactly-once messaging bir broker özelliği değildir; effectively-once bir sistem tasarımıdır.
Exactly-once neden yalan
Bir worker mesajı alır, işler, acknowledgment gönderir — ama acknowledgment ağda kaybolur. Broker mesajı tekrar gönderir. Worker ikinci kez işler. Bu, at-least-once delivery'nin doğasında vardır; broker ne kadar 'exactly-once' iddia ederse etsin, tüketici tarafında duplicate kaçınılmazdır.
Worker mesajı işler → sonuç: Captured
Ack ağda kaybolur
Broker mesajı tekrar gönderir
Worker tekrar işler → sonuç: ??? (çift charge riski)
Sorun mesajın kaç kez geldiği değil; ikinci gelişte ne olduğudur. İkinci gelişte hiçbir yan etki yoksa, effectively-once elde edilmiş demektir.
Defense in depth: tek katman yetmez
Effectively-once iş sonucu, birbirini tamamlayan katmanların birleşimidir. Hiçbiri tek başına yeterli değildir; hepsi birlikte 'en az bir kez gelen mesaj, en fazla bir kez etki eder' sonucunu üretir.
Katman 1: Idempotency key (API)
→ aynı key ile ikinci charge isteği reddedilir
Katman 2: Consumer dedup (messaging)
→ aynı message id ikinci kez işlenmez
Katman 3: DB uniqueness constraint
→ aynı idempotency key ile ikinci satır yazılamaz
Katman 4: Outbox pattern
→ event yalnızca transaction commit ile birlikte yayınlanır
Katman 5: Reconciliation
→ katman 1-4'ün kaçırdığı drift'i periyodik olarak düzeltir
Bir katman başarısız olursa diğeri devreye girer. Idempotency key atlanırsa uniqueness constraint yakalar; constraint atlanırsa reconciliation düzeltir.
Her katmanın sorusu farklıdır
| Katman | Sorusu | Koruduğu |
|---|---|---|
| Idempotency key | Aynı niyet tekrar mı? | API düzeyinde çift charge |
| Consumer dedup | Aynı mesaj tekrar mı? | Messaging düzeyinde çift işlem |
| Uniqueness constraint | Aynı key ile ikinci satır mı? | DB düzeyinde çift kayıt |
| Outbox | Event commit olmadan mı yayınlandı? | Kayıp veya erken event |
| Reconciliation | Local ile PSP uyumsuz mu? | Kaçan her şey |
Idempotent consumer nasıl yazılır
Idempotent consumer'ın kuralı: aynı input, aynı output; ikinci çağrıda yan etki yok.
PaymentCaptured webhook (messageId=wh_991)
→ dedup tablosuna bak: wh_991 işlendi mi?
→ evet → skip (log: duplicate suppressed)
→ hayır → finalize, dedup tablosuna yaz
Finalize adımının kendisi de idempotent olmalıdır: payment zaten Captured ise tekrar event yayınlanmamalı, tekrar order oluşturulmamalıdır. Dedup tablosu messaging katmanını korur; terminal statü kontrolü iş mantığını korur.
Outbox: event ile state aynı transaction'da
Outbox pattern, 'state güncellendi ama event yayınlanmadı' veya 'event yayınlandı ama state güncellenmedi' ikilemini çözer. Event, local transaction ile birlikte outbox tablosuna yazılır; ayrı bir publisher outbox'ı okur ve broker'a gönderir.
BEGIN TRANSACTION
UPDATE payment SET status=Captured
INSERT INTO outbox (event=PaymentCaptured, paymentId=8812)
COMMIT
→ publisher outbox'ı okur → broker'a gönderir
→ gönderim başarılı → outbox satırını siler
Outbox, messaging exactly-once sağlamaz — ama state ile event arasındaki tutarlılığı garanti eder. Reconciliation, outbox'tan kaçanları yakalar.
Sık karıştırılan ayrımlar
❌ Broker exactly-once = sistem exactly-once
✓ Broker dedup + consumer idempotency + DB constraint = effectively-once
❌ Idempotency key her yerde yeterli
✓ Idempotency key API'yi korur; webhook ve async worker ayrı katman ister
❌ Effectively-once = perfect system
✓ Effectively-once = iş sonucu bir kez; tutarsızlık penceresi reconciliation ile kapanır
Delivery guarantee vs business outcome
| Garanti | Ne vaat eder | Ödemelerde yeterli mi |
|---|---|---|
| At-most-once | Mesaj bir kez, kayıp olabilir | Hayır — kayıp ödeme |
| At-least-once | Mesaj en az bir kez, duplicate olabilir | Hayır — tek başına |
| Exactly-once (broker) | Teorik, pratikte tüketici tarafında kırılır | Hayır |
| Effectively-once (sistem) | İş sonucu bir kez | Evet |
Effectively-once kontrol listesi
- API charge istekleri idempotency key ile korunuyor mu?
- Webhook ve async consumer'larda message-id dedup var mı?
- Payment tablosunda idempotency key üzerinde uniqueness constraint var mı?
- State değişikliği ile event yayını outbox pattern ile aynı transaction'da mı?
- Finalize handler terminal statüde tekrar işlem yapmadan skip ediyor mu?
- Reconciliation, katman 1-5'in kaçırdığı drift'i periyodik tarıyor mu?
Bu yazıdan aklında ne kalmalı
- Exactly-once messaging bir yalandır; at-least-once + failure = duplicate kaçınılmazdır.
- Effectively-once iş sonucu, defense in depth ile mümkündür — tek katman yetmez.
- Her koruma katmanı farklı bir soruya cevap verir; hepsi birlikte çalışmalıdır.
- Reconciliation son katmandır; önceki katmanların yerine geçmez, tamamlar.
Broker'ınız exactly-once vaat etse bile, ödeme sisteminiz buna inanmamalı — inanması gereken, effectively-once iş sonucunu defense in depth ile inşa etmektir.
Bir sonraki bölümde bu 22 bölümlük yolculuğun sentezine geçiyoruz: production ödeme motoru tasarım checklist'i.
SSS
Sık sorulan sorular
At-Least-Once Delivery nedir?
Mesaj en az bir kez ulaşır; ağ hatasında tekrar gönderilebilir.
Effectively-Once nedir?
Mesaj birden fazla kez işlense bile iş sonucu (charge, refund, order) yalnızca bir kez gerçekleşir.
"Broker exactly-once = sistem exactly-once" doğru mu?
Broker dedup + consumer idempotency + DB constraint = effectively-once
Bu bölüm neyi sabitler?
Broker satıcıları 'exactly-once semantics' vaat eder. Gerçek şu: dağıtık bir sistemde bir mesajın tam olarak bir kez işlenmesi fiziksel olarak garanti edilemez. Ağ kopar, worker çöker, broker yeniden gönderir. Soru 'mesaj kaç kez geldi' değil; **iş sonucu kaç kez gerçekleşti**. Exactly-once messaging bir yalandır; at-least-once + failure = duplicate kaçınılmazdır. Önceki bölümde recovery pipeline'ın otomasyon önce prensibiyle çalıştığını ve uniqueness duvarlarında kanıta dayalı runbook'ların devreye girdiğini gördük. Bu bölüm, pipeline'ın üzerinde yatan messaging garantilerine iniyor — ve endüstrinin en yaygın yanılgısına: exactly-once delivery.
Ogrenilen Muhendislik Prensipleri
- Exactly-once messaging bir yalandır; effectively-once iş sonucu mümkündür.
- Defense in depth: idempotency, dedup, uniqueness, outbox, reconciliation birlikte çalışır.
- Her koruma katmanı farklı bir soruya cevap verir; tek katman yetmez.
Okumaya devam et
Okumaya devam et
Seride sonraki yazi
Production Ödeme Motoru Tasarlamak
22 bölümlük serinin sentezi: checkout orchestrator ve provider gateway ile production ödeme motoru için mimari checklist.
Seride sonraki yazi
Ö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.
Ayni seriden
Fintech Şirketleri Aslında Ne Arıyor?
Kariyer perspektifi: fintech şirketleri Stripe SDK'sını değil; failure thinking, reconciliation, idempotency ve evidence-driven düşünceyi arıyor.