Bir faturanın güvenilirliği

Klavye: ← → ile gezinin, F tam ekran, O genel bakış.

Tan, ciddi bir ifadeyle

Muhammet Şafak — Görseller

Bir faturanın güvenilirliği

Numara, yazma, tekrar ve sonuç: bir fatura yolda dört kez ters gidebilir.

Muhammet Şafak

Bölüm 01

Numara

E-faturada numara hem mükerrersiz hem boşluksuz olmak zorunda.

Numarayı geç üretirsem race, erken üretirsem gap.

Muhammet Şafak E-fatura entegrasyonunda numara çakışması

İki kısıt

Dört yaklaşım, iki kısıt

Veritabanının kendi sequence'ı (SEQUENCE, AUTO_INCREMENT) rollback'te tüketilen değeri geri vermez; boşluk üretir.
Yaklaşım Mükerrersiz Boşluksuz Kırılma
Gönderimde MAX()+1 Hayır Evet Paralel worker'da çakışma
Enqueue'da üret Evet Hayır Başarısız ya da iptal → gap
DB sequence Evet Hayır Rollback değeri geri vermez → gap
JIT rezervasyon Evet Evet Bedeli: erken commit şart

JIT rezervasyon

Numara, gönderimden hemen önce

  1. Adım 1: Kilitle lockForUpdate
  2. Adım 2: Rezerve et reserved_no boşsa sayaç++
  3. Adım 3: Erken commit status = SENDING
  4. Adım 4: Entegratör kilidin dışında
  5. Adım 5: Retry aynı reserved_no

Kilit DB state'i için tutulur, dış I/O için değil.

Muhammet Şafak Entegratör çağrısı 200 ms ile 2 saniye sürer · sade.dev

Bölüm 02

Teslim

Fatura veritabanına, event RabbitMQ'ya: iki sistem, tek atomik adım yok.

Dual-write

İki sisteme yazmak

Dual-write save() ve publish() ayrı
  • Yayın düşer → kayıp event
  • Rollback olur → hayalet event
  • DB::transaction RabbitMQ'yu kapsamaz
Transactional outbox Yazma tek sisteme iner
  • Fatura ve outbox satırı aynı commit'te
  • Ayrı bir süreç broker'a yayımlar
  • Dual-write tek write'a iner

Tekrar

Tekrar teslim zararsız olmalı

Yalnız at-least-once Idempotent tüketici
Teslim En az bir, bazen iki kez En az bir, bazen iki kez
Kayıt İşlenen id tutulmaz processed_messages, unique kısıt
Transaction İş ve damga ayrı İş ve damga aynı transaction'da
Sonuç Tekrar, etkiyi tekrarlar Effectively-once

Veriyi tek bir sisteme yaz, tekrarı tüketicide bastır, hassas alanı yola çıkmadan mühürle.

Muhammet Şafak Outbox, idempotent tüketim ve alan şifrelemesi

Bölüm 03

Sonuç

Outbox teslimi garanti etti; aynı sonucu garanti etmedi.

Gerçek denklem

sonuç = f(mesaj, gizli girdiler )

Üretim ile tüketim arası milisaniye de olabilir, yirmi dakika da, üç gün de.

Gizli girdiler

Altı gizli girdi

Event-driven bir fatura akışında karşılaşılan altı gizli girdi.
Girdi Somut hâli
Zaman Belge tarihi için o anki saati okumak
Veritabanı Oluşturulurken önek X, gönderilirken Y
Konfigürasyon Aynı izin listesi iki ayrı serviste
Dış sistem "Bu zaten var", ama neyin var olduğu belirsiz
Ortam Bir framework uyarıyı yutar, diğeri exception'a çevirir
Worker Paralel replica, kilit, tekrar teslim

Gürültülü başarısızlık, sessiz yanlış sonuca yeğdir

Dört hamle

  1. Adım 1: Bağlamı dondur üretim anında
  2. Adım 2: Zaman girdidir retry zamanı değiştirmez
  3. Adım 3: Çatalı isimlendir gerekçeyi log'a yaz
  4. Adım 4: Sessizce çözme belirsizlikte dur
Tan, el sallarken

Teşekkürler

muhammetsafak.com/tr/

Karara giren dondurulur, girmeyen referansla taşınır.

Paylaş, göm, indir