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
failed_jobszaten sizin DLQ’nuz. Sınır dolunca Laravel işi otomatikfailed_jobstablosuna taşır — ekstra bir altyapı kurmanıza gerek yok, Dead Letter Queue zaten budur.- 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.
- 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. - 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ı
- Retry’ı sınırlayın. İşin üstüne
tries(ya damaxExceptions) ve birbackoffkoyun. 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. - İş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. - Alert kurun. Bir
JobFailedlistener’ı yazın; işfailed_jobs’a düştüğü an Slack/Sentry’ye bildirim göndersin. Yöneticiler anında haberdar olmalı. İncelemeden sonraqueue:retryile düzeltilen işi replay edersiniz. - 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. - 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
Yorumlar
Yorum yapmak için GitHub hesabınızla giriş yapmanız yeterli. Yorumlar GitHub Discussions üzerinde saklanır.