Oyun Kitabı

Ödeme Hata Taksonomisi (Odeme Hata Taksonomisi)

Timeout, 429, 5xx, business decline ve infrastructure hatası aynı şey değildir. Her kategori farklı bir retry politikası ister.

Dağıtık Ödeme Motoru (Distributed Payment Engine)

Bolum 11 / 22

Capture ile complete arasındaki boşluğu kapatan dağıtık ödeme mimarisi serisi.

Distributed payment engine architecture diagram

Önceki bölümde PaymentFailed gibi semantik event'lerin provider'ın statü kodlarını gizlediğini gördük. Fakat tek bir PaymentFailed event'i bile yeterli değildir; çünkü 'başarısız' kelimesi çok farklı gerçekleri kapsar.

Bir kartın reddedilmesi, bir ağ timeout'u, PSP'nin 429 döndürmesi ve PSP'nin 500 döndürmesi hepsi 'başarısız' olarak görünebilir; ama her biri tamamen farklı bir aksiyon gerektirir. Bu bölüm, bu farkları görünür kılan bir taksonomi kurmayı ele alıyor.

PaymentFailed
  ├─ Business Decline    (kart reddedildi — retry etme)
  ├─ Timeout             (belirsiz sonuç — dikkatli retry)
  ├─ Rate Limited (429)  (çok istek — backoff ile retry)
  └─ Infrastructure (5xx) (provider tarafı arıza — retry)

Kavramlar ilk geçtiği yerde

📦 Business Decline
PSP'nin, kartın kendisiyle ilgili bir nedenle isteği reddetmesi: yetersiz bakiye, dolandırıcılık şüphesi.

📦 Transient Hata
Aynı isteğin tekrar denenmesi mantıklı olan, geçici bir arıza: timeout, 5xx, 429.

📦 Permanent Hata
Tekrar denemenin sonucu değiştirmeyeceği hata: geçersiz kart numarası, desteklenmeyen para birimi.

📦 Belirsiz Sonuç
İsteğin PSP'ye ulaşıp ulaşmadığının bilinmediği durum: bağlantı timeout'u.

Business decline'ı retry etmek zaman kaybıdır; belirsiz sonucu retry etmemek ise gerçek bir kaçırılmış ödeme riskidir. Taksonomi, bu iki riski birbirinden ayırmak için var.

Dört temel kategori

Business decline: PSP isteği aldı, işledi ve kararını verdi — kart reddedildi. Bu bir sistem hatası değildir, bir iş kararıdır. Tekrar denemek sonucu değiştirmez; kullanıcıya başka bir ödeme yöntemi önermek gerekir.

Timeout / belirsiz sonuç: İstek gönderildi ama yanıt hiç gelmedi. Burada tehlikeli olan şudur — ödeme PSP tarafında gerçekleşmiş olabilir, sadece yanıt sizde kaybolmuştur. Bu kategori kör bir 'tekrar dene' ile ele alınamaz; önce durum sorgulanmalı (idempotency key ile), sonra karar verilmelidir.

Rate limited (429): PSP, istek hacmini kontrol etmek için sizi geçici olarak reddediyor. Bu bir hata değil, bir sinyal. Hemen tekrar denemek durumu kötüleştirir; backoff ile beklemek gerekir.

Infrastructure (5xx): PSP'nin kendi tarafında bir arıza var. İstek işlenmemiştir, tekrar denemek genellikle güvenlidir — ama sürekli 5xx alınıyorsa bu bir circuit breaker sinyalidir.

Hata alındı
  │
  ├─ PSP isteği net biçimde reddetti mi? → Business Decline → retry etme
  │
  ├─ Yanıt hiç gelmedi mi? → Belirsiz Sonuç → önce durumu sorgula
  │
  ├─ 429 mu? → Rate Limited → backoff ile retry
  │
  └─ 5xx mi? → Infrastructure → retry, ama circuit breaker'ı izle

Neden tek bir 'retry et' kuralı yeterli değil

Tüm hataları aynı retry mantığıyla ele alan bir worker iki şekilde başarısız olur: business decline'ları anlamsızca tekrar dener (kullanıcı deneyimini geciktirir, bazen kart ağı limitlerini zorlar), ya da belirsiz sonuçları hiç retry etmeden bırakır (gerçekte başarılı olmuş bir ödemeyi sistemin unutmasına yol açar). Taksonomi, her hatayı doğru kutuya koyarak bu iki riski de azaltır.

Taksonomiyi kodda nasıl temsil ederiz

Semantik event'in failureReason alanı, provider'ın ham hata metnini değil, bu dört kategoriden birini taşımalıdır. Provider gateway, ham hatayı bu kategoriye eşlemekle sorumludur — bu, önceki bölümdeki çeviri katmanının bir uzantısıdır.

failureReason Retry uygun mu Aksiyon
BusinessDecline Hayır Kullanıcıya başka yöntem öner
AmbiguousTimeout Önce sorgula Durum sorgusu sonra karar
RateLimited Evet Backoff ile retry
InfrastructureError Evet Retry + circuit breaker izle

Sık karıştırılan ayrımlar

❌ Her hata retry edilmelidir
✓ Business decline retry edilmemelidir; sonuç değişmez

❌ Timeout = hata yok, sadece tekrar dene
✓ Timeout = belirsizlik; önce gerçek durum sorgulanmalı

❌ 429 bir arızadır
✓ 429 bir sinyaldir; sistem sizi kasıtlı olarak yavaşlatıyor

Kategoriler arası hızlı karşılaştırma

Kategori Sonuç belli mi Retry mantıklı mı Tipik neden
Business Decline Evet Hayır Kart, bakiye, dolandırıcılık
Timeout Hayır Önce sorgula Ağ, PSP yavaşlığı
Rate Limited Evet Evet (bekleyerek) Hacim kontrolü
Infrastructure Evet Evet PSP tarafı arıza

Taksonomi kurarken kontrol listesi

  1. Provider'ın döndürdüğü her hata kodu, dört kategoriden birine açıkça eşleniyor mu?
  2. Eşlenmemiş yeni bir hata kodu geldiğinde sistem varsayılan olarak durumu mu sorguluyor, yoksa körlemesine mi retry ediyor? (Doğru varsayılan: durumu sorgula.)
  3. Timeout senaryosunda, retry öncesi durum sorgusu (status check) gerçekten uygulanıyor mu?
  4. 429 için backoff süresi, PSP'nin Retry-After başlığını (varsa) dikkate alıyor mu?
  5. 5xx sıklığı, circuit breaker'ı tetikleyecek bir metrik olarak izleniyor mu?
  6. Business decline sonrası kullanıcı akışı, retry döngüsüne hiç girmiyor mu?

Bu yazıdan aklında ne kalmalı

  1. 'Başarısız' tek bir durum değildir; en az dört farklı aksiyon gerektiren dört farklı gerçektir.
  2. Business decline retry edilmez; timeout körlemesine retry edilmez, önce sorgulanır.
  3. 429 bir sinyal, 5xx bir arızadır; ikisi de retry edilir ama farklı disiplinle.
  4. Taksonomi, hatayı ham provider metninden değil, kendi failureReason enum'unuzdan okunabilir kılar.

Bir retry politikası, hatayı anlamadan yazıldıysa; işe yaramaz olmakla kalmaz, sessizce zarar verir.

Bir sonraki bölümde bu dört kategorinin her biri için gerçek retry algoritmasını — backoff, jitter, cap ve circuit breaker'ı — kuracağız.

SSS

Sık sorulan sorular

Business Decline nedir?

PSP'nin, kartın kendisiyle ilgili bir nedenle isteği reddetmesi: yetersiz bakiye, dolandırıcılık şüphesi.

Transient Hata nedir?

Aynı isteğin tekrar denenmesi mantıklı olan, geçici bir arıza: timeout, 5xx, 429.

"Her hata retry edilmelidir" doğru mu?

Business decline retry edilmemelidir; sonuç değişmez

Bu bölüm neyi sabitler?

Bir kartın reddedilmesi, bir ağ timeout'u, PSP'nin 429 döndürmesi ve PSP'nin 500 döndürmesi hepsi 'başarısız' olarak görünebilir; ama her biri tamamen farklı bir aksiyon gerektirir. Bu bölüm, bu farkları görünür kılan bir taksonomi kurmayı ele alıyor. 'Başarısız' tek bir durum değildir; en az dört farklı aksiyon gerektiren dört farklı gerçektir. Önceki bölümde `PaymentFailed` gibi semantik event'lerin provider'ın statü kodlarını gizlediğini gördük. Fakat tek bir `PaymentFailed` event'i bile yeterli değildir; çünkü 'başarısız' kelimesi çok farklı gerçekleri kapsar.

Ogrenilen Muhendislik Prensipleri

  • Başarısız tek bir durum değildir; her kategori farklı bir aksiyon gerektirir.
  • Belirsiz sonuç körlemesine retry edilmez, önce sorgulanır.
  • 429 bir sinyaldir, arıza değil — disiplinle beklenir.

Okumaya devam et

Okumaya devam et

Seride sonraki yazi

Seride sonraki yazi

Ayni seriden

Paylaş