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

> İşe `tries` ve `backoff` verin: sınır dolunca Laravel işi `failed_jobs`'a taşır, `JobFailed` listener'ı alert eder, düzelen işi `queue:retry` geri oynatır.

- Soruldu: 2026-06-04
- Yanıtlandı: 2026-06-07
- Soran: Gökhan
- Etiketler: dayaniklilik, queue, laravel
- Kaynak: https://www.muhammetsafak.com.tr/sor-bakalim/kuyrukta-poison-pill-ve-dead-letter-queue-yonetimi/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
**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?


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.

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.

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. **`failed_jobs` sizin yerleşik 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. İşin üstüne `failed()` metodu tanımlayıp temizlik/telafi mantığını oraya koyun.
3. **Alert kurun.** Bir `JobFailed` listener'ı yazın; iş `failed_jobs`'a düştüğü an Slack/Sentry'ye bildirim göndersin. "Sessizce başarısız olan iş" en kötü senaryodur; yöneticiler anında haberdar olmalı. İncelemeden sonra `queue:retry` ile düzeltilen işi replay edersiniz.
4. **Fatal Error'ı ayrı ele alın.** 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. Bunun için "bu job id'yi N kez gördüm" sayacı (Redis'te) tutup eşiği aşınca işi zorla `failed_jobs`'a atın.
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

- [Laravel Queue ve Supervisor ile Asenkron İşlemler](/blog/laravel-queue-ve-supervisor-ile-asenkron-islemler/) — Blog
- [Dağıtık sistemde Saga Pattern ile eventual consistency'yi nasıl tasarlarım?](https://www.muhammetsafak.com.tr/sor-bakalim/dagitik-sistemde-saga-pattern-ile-eventual-consistency/) — Sor Bakalım
- [Üçüncü parti API bağımlılığında Circuit Breaker'ı nasıl kurarım?](https://www.muhammetsafak.com.tr/sor-bakalim/ucuncu-parti-api-icin-circuit-breaker-deseni/) — Sor Bakalım
- [İşlediğim satırları aynı anda güncellerken chunk yerine chunkById mı kullanmalıyım?](https://www.muhammetsafak.com.tr/sor-bakalim/isledigim-satirlari-ayni-anda-guncellerken-chunk-yerine-chunkbyid-mi-kullanmaliyim/) — Sor Bakalım
