Oyun Kitabı

Ham Sağlayıcı Verisi Yerine Anlamsal Olay (Semantic Event) (Ham Provider Payload Yerine Semantik Event)

Provider gateway'in aldığı webhook, downstream'e PSP'nin event adıyla mı, yoksa PaymentCaptured/PaymentFailed gibi semantik bir olayla mı ulaşmalı?

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

Bolum 10 / 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 orchestrator'ın PSP SDK'sını hiç görmemesi gerektiğini gördük. Aynı sınır, senkron çağrının bir adım ötesinde tekrar karşımıza çıkar: provider'dan gelen webhook.

Bir PSP webhook'u genellikle kendi iç veri modelini taşır: provider'a özgü event tipi adı, provider'a özgü statü kodları, provider'a özgü nesne yapısı. Bu payload'ı olduğu gibi mesaj kuyruğuna veya event akışına koymak, provider'ın şemasını tüm downstream tüketicilere sızdırmak demektir.

PSP Webhook
  { type: 'charge.succeeded', data: { object: {...} } }
      ▼
Provider Gateway (çeviri)
      ▼
Semantik event
  PaymentCaptured { paymentId, amount, currency }

Bu bölüm, çeviri katmanının neden ihmal edilemeyecek bir sorumluluk olduğunu ele alıyor.

Kavramlar ilk geçtiği yerde

📦 Semantik Event
İş diliyle adlandırılmış, provider'a hiç referans vermeyen olay: PaymentCaptured, PaymentFailed.

📦 Ham Provider Payload
PSP'nin webhook body'sinde gönderdiği, kendi iç modelini taşıyan orijinal veri.

📦 Çeviri Katmanı (Translator)
Ham payload'ı okuyup semantik event'e dönüştüren, gateway içinde yaşayan bileşen.

📦 Event Sözleşmesi Sahipliği
Semantik event'in alanlarını ve anlamını kimin belirlediği; burada her zaman gateway.

charge.succeeded bir provider'ın kendi iç terminolojisidir; PaymentCaptured ise sizin domain'inizin gerçeğidir. İkisi aynı anda değişmez: provider event adını değiştirebilir, semantik event adı sabit kalır.

Ham payload'ı olduğu gibi taşımanın maliyeti

En hızlı entegrasyon yolu, webhook body'sini ayrıştırmadan mesaj broker'ına basmaktır. Kısa vadede çalışır: tüketici de aynı payload'ı ayrıştırır. Fakat bu, provider'ın şema değişikliklerini her tüketiciye doğrudan yayar. PSP bir alanın adını değiştirdiğinde, sizin kontrolünüzde olmayan bir olay, sizin sistemlerinizin çoğunda aynı anda kırılma yaratır.

Ham payload yayılırsa
  PSP şema değişikliği → N tüketici aynı anda etkilenir

Semantik event yayılırsa
  PSP şema değişikliği → sadece gateway'in çeviri katmanı güncellenir

Çeviri katmanı ne yapar, ne yapmaz

Çeviri katmanı, provider'a özgü statü kodlarını semantik bir enum'a eşler, tutarsız veya eksik alanları normalize eder, gerekliyse eksik veriyi (örneğin tutar, para birimi) local kayıttan tamamlar. Yapmaması gereken şey, iş kararı vermektir: 'Bu ödeme neden başarısız oldu, ne yapılmalı' sorusunun cevabı orchestrator'ın işidir, çeviri katmanının değil.

Webhook geldi
  → provider event tipini oku
  → statü eşleme tablosuna bak
  → semantik event oluştur
  → local correlation id ile eşle
  → yayınla (Outbox üzerinden)

Eşleme tablosu somut bir tasarım aracıdır

Provider'ın onlarca event tipi olabilir; sizin semantik event kümeniz çok daha küçük ve stabil olmalıdır.

Provider event Semantik event
charge.succeeded PaymentCaptured
charge.failed PaymentFailed
charge.dispute.created PaymentDisputed
payment_intent.requires_action PaymentActionRequired

Bu tablo kod incelemesinde okunabilir olmalı; yeni bir provider event'i geldiğinde 'bu hangi semantik event'e karşılık gelir' sorusu bir satırlık bir karar olmalı, kod tabanına dağılmış bir if-else zinciri değil.

Sıra ve tekrar teslim garantisi hâlâ geçerli

Çeviri katmanı, webhook'un mükerrer geldiği veya sıra dışı geldiği senaryoları da ele almalıdır. Provider aynı webhook'u ağ hatası nedeniyle iki kez gönderebilir; semantik event üretilirken bu, event üretiminin idempotent olmasını gerektirir — aynı webhook id'si ikinci kez geldiğinde aynı semantik event yeniden yayınlanmamalıdır (veya downstream idempotent olarak tasarlanmalıdır).

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

❌ Webhook = Event
✓ Webhook bir bildirim tetikleyicisidir; semantik event iş dilindeki gerçektir

❌ Ham payload'ı saklamak gereksizdir
✓ Ham payload tanılama için saklanır, ama yalnızca gateway'in kendi arşivinde

❌ Eşleme tablosu bir kere yazılır, bitmiştir
✓ Provider yeni event tipleri ekledikçe tablo canlı bir sözleşmedir

Ham geçiş ile semantik çeviri

Kriter Ham geçiş Semantik çeviri
Downstream'in provider bilgisi Gerekli Gereksiz
Şema değişikliğine kırılganlık Yüksek Düşük
Tanılama için ham veri Kaybolabilir Gateway'de saklanır
Yeni PSP eklemek Tüketicileri etkiler Sadece eşleme tablosunu etkiler

Çeviri katmanını tasarlarken kontrol listesi

  1. Downstream tüketicilerin herhangi biri provider'a özgü bir alan adı veya statü kodu okuyor mu?
  2. Eşleme tablosu tek bir yerde mi tanımlı, yoksa kod tabanına dağılmış mı?
  3. Ham webhook payload'ı, tanılama için gateway'in kendi arşivinde saklanıyor mu?
  4. Aynı webhook iki kez geldiğinde aynı semantik event iki kez mi yayınlanıyor?
  5. Yeni bir provider event tipi geldiğinde, henüz eşlenmemişse ne olur — sessizce yutulur mu, yoksa görünür bir uyarı mı üretir?

Beşinci soru özellikle önemlidir: sessizce yutulan bilinmeyen event'ler, üretimde en sinsi veri kaybı biçimlerinden biridir.

Bu yazıdan aklında ne kalmalı

  1. Downstream hiçbir zaman provider'ın event adını veya statü kodunu görmemelidir.
  2. Çeviri katmanı bir eşleme tablosu ve normalize etme mantığıdır, iş kararı vermez.
  3. Ham payload tanılama için saklanır ama yalnızca gateway'in kendi sınırında kalır.
  4. Bilinmeyen provider event'leri sessizce yutulmamalı, görünür bir sinyal üretmelidir.

Bir event'in semantik olup olmadığını anlamanın en kolay yolu: adını provider'ın belgelerinden değil, kendi domain sözlüğünüzden okuyabiliyor olmanızdır.

Bir sonraki bölümde bu semantik event'lerin taşıdığı başarısızlık bilgisini derinleştiriyoruz: her PaymentFailed aynı anlama gelmez, bir hata taksonomisine ihtiyacımız var.

SSS

Sık sorulan sorular

Semantik Event nedir?

İş diliyle adlandırılmış, provider'a hiç referans vermeyen olay: PaymentCaptured, PaymentFailed.

Ham Provider Payload nedir?

PSP'nin webhook body'sinde gönderdiği, kendi iç modelini taşıyan orijinal veri.

"Webhook = Event" doğru mu?

Webhook bir bildirim tetikleyicisidir; semantik event iş dilindeki gerçektir

Bu bölüm neyi sabitler?

Bu bölüm, çeviri katmanının neden ihmal edilemeyecek bir sorumluluk olduğunu ele alıyor. Downstream hiçbir zaman provider'ın event adını veya statü kodunu görmemelidir. Önceki bölümde orchestrator'ın PSP SDK'sını hiç görmemesi gerektiğini gördük. Aynı sınır, senkron çağrının bir adım ötesinde tekrar karşımıza çıkar: provider'dan gelen webhook.

Ogrenilen Muhendislik Prensipleri

  • Downstream provider'ın event adını değil, sizin domain'inizin gerçeğini görmelidir.
  • Eşleme tablosu canlı bir sözleşmedir, bir kerelik kod değil.
  • Bilinmeyen provider event'i sessizce yutulmamalı, görünür olmalı.

Okumaya devam et

Okumaya devam et

Seride sonraki yazi

DENEME

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

Seride sonraki yazi

Ayni seriden

Paylaş