Oyun Kitabı

Lease ile Veritabanı Destekli İşler (Lease İle Veritabani Destekli İsler)

Conditional UPDATE ile lease alma, sıkışmış işleri kurtaran watcher ve neden yalnızca mesaj Nack etmek production ödemede yetmez.

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

Bolum 13 / 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 retry algoritmasını kurduk; ama bu algoritma bir işin hangi worker tarafından çalıştırıldığını varsayıyordu. Birden çok worker aynı iş kuyruğundan çekiyorsa, aynı ödeme işi iki worker tarafından aynı anda işlenebilir mi?

Mesaj broker'ları bu sorunu 'visibility timeout' veya 'ack/nack' ile çözer. Fakat veritabanı destekli bir iş kuyruğunda (birçok ödeme sisteminde tercih edilen yaklaşım, çünkü iş durumu zaten veritabanında yaşar) aynı garanti lease deseniyle sağlanır.

Worker A                          Worker B
   │ SELECT ... FOR UPDATE?           │
   │ ya da conditional UPDATE          │
   ▼                                  ▼
  Job'ı kilitlemeye çalışır      Job'ı kilitlemeye çalışır
   → sadece biri kazanır

Kavramlar ilk geçtiği yerde

📦 Lease
Bir worker'ın bir işi belirli bir süre için 'sahiplendiğini' işaretleyen zaman damgalı kayıt.

📦 Conditional UPDATE
Sadece beklenen koşul (örn. status = Pending) doğruysa satırı güncelleyen atomik SQL işlemi.

📦 Lease süresi (Lease TTL)
Bir worker'ın işi ne kadar süreyle sahiplenebileceğinin üst sınırı; bu süre geçince iş tekrar alınabilir hale gelir.

📦 Stuck Watcher
Lease'i süresi dolmuş ama tamamlanmamış işleri periyodik olarak tarayıp yeniden kuyruğa alan arka plan süreci.

Lease bir kilit değildir; kilidi tutan process çökerse kilit sonsuza kadar kalabilir. Lease'in süresi olduğu için, worker çökse bile iş bir süre sonra otomatik olarak serbest kalır.

Lease almanın atomik yolu

Bir işi almak için önce okuyup sonra güncellemek (read-then-write) bir yarış durumuna açıktır: iki worker aynı satırı okuyabilir, ikisi de 'boş' görebilir, ikisi de güncellemeye çalışabilir. Doğru yol, okuma ve koşulu aynı atomik ifadeye taşımaktır:

UPDATE payment_jobs
SET status = 'Processing',
    lease_owner = :workerId,
    lease_until = now() + interval '60 seconds'
WHERE id = :jobId
  AND (status = 'Pending' OR (status = 'Processing' AND lease_until < now()))
RETURNING id;

Bu UPDATE hiçbir satır döndürmezse, iş zaten başka bir worker tarafında ya da hâlâ geçerli bir lease altındadır — worker sessizce bir sonraki işe geçer. Satır döndüyse, o worker artık işin tek sahibidir; ta ki lease süresi dolana kadar.

Lease süresi neden heartbeat ile uzatılmalı

Sabit bir lease süresi (örn. 60 saniye) her işlem için yetmeyebilir. Uzun sürebilecek bir işlem (örneğin bir PSP çağrısı beklenmedik şekilde uzarsa), lease süresi dolmadan önce heartbeat ile uzatılmalıdır:

Worker işe başlar → lease_until = now + 60s
  ... iş sürüyor ...
Worker heartbeat gönderir → lease_until = now + 60s (yenilenir)
  ... iş tamamlanır ...
Worker status = Completed olarak işaretler

Heartbeat gönderemeyen bir worker (çökmüş, ağdan kopmuş) lease'i yenileyemez; süre dolar ve iş tekrar alınabilir hale gelir. Bu, çökme senaryosunun otomatik olarak ele alınmasını sağlayan mekanizmadır.

Stuck watcher: lease'i süresi dolmuş işleri kim fark eder

Lease süresi dolduğunda iş otomatik olarak 'kurtarılmaz' — bir worker'ın onu tekrar SELECT etmesi gerekir. Bu yüzden periyodik çalışan bir watcher süreci, lease'i süresi dolmuş ama hâlâ Processing durumunda kalan işleri tarar ve bunları tekrar alınabilir hale getirir (veya doğrudan yeni bir worker'a atar).

Watcher (her 30 saniyede bir)
  SELECT id FROM payment_jobs
  WHERE status = 'Processing' AND lease_until < now()
  → bu işler 'stuck' olarak işaretlenir veya doğrudan Pending'e döndürülür

Watcher olmadan, çökmüş bir worker'ın bıraktığı iş sonsuza kadar 'Processing' görünebilir; kimse fark etmeden bir ödeme asla tamamlanmaz.

Neden yalnızca broker'ın Nack'i yeterli değil

Bir mesaj broker'ında bir worker mesajı Nack ederse (veya visibility timeout dolarsa), mesaj tekrar kuyruğa döner. Bu, DB'deki lease'e çok benzer — fakat iki fark önemlidir: birincisi, broker'ın kendi görünürlük penceresi genellikle iş durumunuzun kalıcı kaydıyla senkron değildir (mesaj kaybolabilir, ya da iki kez teslim edilebilir); ikincisi, Nack yalnızca 'bu mesajı bırak' der, işin hangi aşamada kaldığını veya kaç kez denendiğini kalıcı olarak bilmez. Veritabanı destekli lease, iş durumunu ve deneme geçmişini aynı transaction sınırında, sorgulanabilir biçimde tutar.

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

❌ Lease = kilit (lock)
✓ Lease süresi dolan bir zaman sınırıdır; kilit process çökerse sonsuza kalabilir

❌ Read-then-write yeterlidir
✓ Read-then-write yarış durumuna açıktır; conditional UPDATE atomik olmalıdır

❌ Nack, lease'in yerini tamamen tutar
✓ Nack mesaj görünürlüğünü yönetir; lease iş durumunu ve deneme geçmişini kalıcı olarak tutar

DB-backed lease ile broker visibility timeout karşılaştırması

Kriter Broker visibility timeout DB-backed lease
Durum sorgulanabilirliği Sınırlı SQL ile tam
Deneme geçmişi kalıcılığı Broker'a bağlı Kolayca aynı satırda
Stuck job'ı tespit etme Dolaylı Doğrudan sorgu ile

Lease tasarlarken kontrol listesi

  1. Lease alma işlemi tek bir atomik UPDATE ... WHERE ifadesi mi, yoksa read-then-write mi?
  2. Lease süresi, en uzun beklenen işlem süresinden gerçekten uzun mu?
  3. Uzun sürebilecek işlemler için heartbeat ile lease yenileme var mı?
  4. Stuck watcher periyodik çalışıyor mu, yoksa lease süresi dolan işler sonsuza kadar 'Processing' mi kalıyor?
  5. lease_owner alanı, hangi worker instance'ının işi aldığını tanılama için saklıyor mu?
  6. Deneme sayısı, her lease alımında artırılıp kalıcı olarak saklanıyor mu?

Bu yazıdan aklında ne kalmalı

  1. Lease bir kilit değildir; zaman sınırlı bir sahiplik iddiasıdır ve otomatik olarak sona erer.
  2. Lease almak, atomik bir conditional UPDATE gerektirir; read-then-write yarış durumuna açıktır.
  3. Uzun işlemler heartbeat ile lease'i yenilemelidir; aksi halde lease erken sona erebilir.
  4. Stuck watcher, çökmüş worker'ların bıraktığı işleri kurtaran zorunlu bir arka plan sürecidir.

Bir iş kuyruğunun güvenilirliği, mutlu yolda değil; bir worker'ın ortada çöktüğü anda test edilir.

Bir sonraki bölümde bu lease mekanizmasının üzerine kurulan bir worker türünü inceliyoruz: PSP'de başarılı ama sistemde hâlâ bekleyen ödemeleri iyileştiren mutabakat worker'ı.

SSS

Sık sorulan sorular

Lease nedir?

Bir worker'ın bir işi belirli bir süre için 'sahiplendiğini' işaretleyen zaman damgalı kayıt.

Conditional UPDATE nedir?

Sadece beklenen koşul (örn. status = Pending) doğruysa satırı güncelleyen atomik SQL işlemi.

"Lease = kilit (lock)" doğru mu?

Lease süresi dolan bir zaman sınırıdır; kilit process çökerse sonsuza kalabilir

Bu bölüm neyi sabitler?

Mesaj broker'ları bu sorunu 'visibility timeout' veya 'ack/nack' ile çözer. Fakat veritabanı destekli bir iş kuyruğunda (birçok ödeme sisteminde tercih edilen yaklaşım, çünkü iş durumu zaten veritabanında yaşar) aynı garanti **lease** deseniyle sağlanır. Lease bir kilit değildir; zaman sınırlı bir sahiplik iddiasıdır ve otomatik olarak sona erer. Önceki bölümde retry algoritmasını kurduk; ama bu algoritma bir işin *hangi worker tarafından* çalıştırıldığını varsayıyordu. Birden çok worker aynı iş kuyruğundan çekiyorsa, aynı ödeme işi iki worker tarafından aynı anda işlenebilir mi?

Ogrenilen Muhendislik Prensipleri

  • Lease bir kilit değildir; zaman sınırlıdır ve otomatik sona erer.
  • Lease almak atomik conditional UPDATE gerektirir, read-then-write değil.
  • Stuck watcher olmadan çökmüş worker'ın işi sonsuza kadar kaybolabilir.

Okumaya devam et

Okumaya devam et

Seride sonraki yazi

Seride sonraki yazi

Ayni seriden

Paylaş