İçeriğe geç
Muhammet Şafak
en
Soran: Gökhan Cevaplandı:

Kuyrukta poison pill (zehirli mesaj) ve Dead Letter Queue'yu nasıl yönetirim?


Soru

Laravel Queue (Redis) üzerinde bir job, üçüncü parti bir kütüphanedeki bug yüzünden her işlendiğinde Fatal Error verip worker'ı çökertiyor. Laravel işi otomatik retry ediyor ve tekrar çöküyor; bu zehirli mesaj tüm kuyruğu bloke ediyor. Bu hatalı mesajları ana kuyruktan ayırıp incelemek üzere Dead Letter Queue'ya taşıyan ve yöneticileri uyaran iş akışını nasıl kurarım?

Cevap

Kısa cevap: Her seferinde patlayan ve sonsuza dek otomatik retry edilen bir iş, kuyruğu kilitleyip worker’ı çökertir — buna poison pill (zehirli mesaj) denir. Çözüm retry’ı sınırlamak ve hatalı işi yeniden kuyruğa atmak yerine bir DLQ’ya düşürmek.

Kısa cevap

Sizin yaşadığınız şey klasik: iş sürekli aynı yerde patlıyor, Laravel “tekrar deneyeyim” diyor, tekrar patlıyor, kuyruk ilerleyemiyor. Döngüyü kırmanız gerekiyor. Retry’ın güvenli olabilmesi işin idempotent olmasına bağlı; aynı isteği güvenle tekrarlamanın kurallarını idempotency yazısında ayrıntılandırmıştım.

Neden

  1. failed_jobs zaten sizin DLQ’nuz. Sınır dolunca Laravel işi otomatik failed_jobs tablosuna taşır — ekstra bir altyapı kurmanıza gerek yok, Dead Letter Queue zaten budur.
  2. Fatal Error normal retry yolundan geçmez. Exception değil, worker’ı komple öldüren Fatal Error için Laravel’in normal retry’ı işlemez. Supervisor worker’ı yeniden başlatır ama aynı iş tekrar çekilirse döngü kapanmaz.
  3. Sessizce başarısız olan iş en kötü senaryodur. failed_jobs’a düşen bir iş kimseye haber vermiyorsa kuyruk ilerler ama o işin karşılığı olan sonuç hiç gerçekleşmez.
  4. Tek bir kötü iş tüm kuyruğu aç bırakır. Riskli iş tipleri diğerleriyle aynı kuyrukta çalışıyorsa, bir zehirli mesaj bütün işlerin sırasını tıkar.

Ne yapmalı

  1. Retry’ı sınırlayın. İşin üstüne tries (ya da maxExceptions) ve bir backoff koyun. Böylece iş 3-5 kez denenir, her seferinde sonsuza dek değil. Belirlenen sınıra ulaşınca Laravel onu yeniden kuyruğa atmayı bırakır.
  2. İşe failed() metodu tanımlayın. Temizlik/telafi mantığını oraya koyun; iş DLQ’ya düştüğünde yarım kalan yan etkiler geri sarılsın.
  3. Alert kurun. Bir JobFailed listener’ı yazın; iş failed_jobs’a düştüğü an Slack/Sentry’ye bildirim göndersin. Yöneticiler anında haberdar olmalı. İncelemeden sonra queue:retry ile düzeltilen işi replay edersiniz.
  4. Fatal Error için sayaç tutun. “Bu job id’yi N kez gördüm” sayacını (Redis’te) tutup eşiği aşınca işi zorla failed_jobs’a atın; Supervisor’ın worker’ı ayağa kaldırması tek başına döngüyü kapatmaz.
  5. Kuyrukları riske göre ayırın, işleri idempotent yapın. Riskli iş tiplerini ayrı bir kuyrukta çalıştırın ki tek bir kötü iş tüm diğerlerini aç bırakmasın. Ayrıca işleri idempotent yazın; retry güvenli olsun, iki kez çalışsa da yan etki birikmesin.

Sonuç: Sınırlı retry + failed_jobs DLQ + alert + queue:retry ile replay. Hiçbir işin sınırsız retry edilmesine izin vermeyin; sınırsız retry, tek bir zehirli mesajı tüm sistemi durduran bir silaha çevirir.

İlgili Yazılar

Paylaş:

Yorumlar

Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.

Diğer Sorular

Tüm sorular

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi