Bir e-ticaret sitesinin checkout (ödeme) akışını tasarlayın. Stok tutarlılığını ve çift ödemeyi nasıl önlersiniz?
Cevap
Checkout'un iki kritik riski vardır: aynı ürünün stoktan fazla satılması (overselling) ve aynı siparişin iki kez ücretlendirilmesi. Çözümün özü: stok için atomik rezervasyon, ödeme için idempotency key ve ödeme sonucunun webhook ile doğrulanması.
Akış
- Sepet -> sipariş oluştur:
orderskaydıpending_paymentdurumunda oluşturulur, fiyatlar sunucuda yeniden hesaplanır (client'ın gönderdiği fiyata asla güvenilmez). - Stok rezervasyonu: stok atomik olarak düşülür ve rezervasyona süre verilir (ör. 15 dk).
- Ödeme: ödeme sağlayıcısında (Stripe, iyzico) payment intent oluşturulur, sipariş ID'sine bağlı bir idempotency key ile. 3D Secure gerekiyorsa kullanıcı yönlendirilir.
- Webhook: sağlayıcı
payment.succeededolayını gönderir; siparişpaidolur, rezervasyon kalıcılaşır, e-posta ve kargo süreçleri kuyruğa atılır. - Süre aşımı: ödenmeyen siparişin rezervasyonu bir job ile serbest bırakılır.
-- Atomik stok düşme: aynı anda iki istek gelse de stok eksiye düşmez
UPDATE inventory SET available = available - $2
WHERE product_id = $1 AND available >= $2
RETURNING available;
-- 0 satır dönerse stok yetersizÇift ödemeyi önleme
- Frontend: "Öde" butonu tıklanınca devre dışı bırakılır; ama bu tek başına yetmez.
- Backend: her checkout denemesinin bir idempotency key'i olur; aynı key ile gelen ikinci istek yeni ödeme oluşturmaz, ilk sonucu döner.
- Sağlayıcı: Stripe gibi API'ler
Idempotency-Keybaşlığını destekler. - Webhook işleyicisi: olay ID'si işlenmiş olaylar tablosunda tutulur; aynı olay tekrar gelirse yok sayılır. Webhook imzası doğrulanır.
Neden webhook?
Kullanıcı ödeme sayfasından sonra tarayıcıyı kapatabilir veya redirect kaybolabilir. Siparişin "ödendi" durumuna geçişi client redirect'ine değil, sunucudan sunucuya gelen doğrulanmış olaya bağlanmalıdır. Redirect sonrası sayfa sadece durumu gösterir (gerekirse polling yapar).
Dağıtık tutarlılık
Sipariş, stok ve ödeme farklı servislerdeyse dağıtık transaction yerine Saga deseni kullanılır: her adımın telafi (compensation) işlemi vardır (ödeme başarısız -> stok iade). Olayların kaybolmaması için outbox pattern ile DB yazımı ve olay yayımlama aynı transaction'da yapılır.
İlgili Sistem Tasarımı soruları
- Dikey ve yatay ölçekleme arasındaki fark nedir?
- Hangi cache stratejilerini biliyorsunuz?
- REST ile GraphQL arasındaki farklar nelerdir?
- Bit.ly benzeri bir URL kısaltma servisi tasarlayın.
- Google Docs benzeri gerçek zamanlı ortak düzenleme yüksek seviyede nasıl tasarlanır?
- CDN nedir, nasıl çalışır ve hangi durumlarda kullanılır?
Bu konuda başka bir soru biliyor musun?
Mülakatta karşılaştığın soruları ekle, onaylandıktan sonra yayına alınsın.