İçeriğe geç
Can Uğurlu
Geri dön

failed_jobs tablosuna bakmıyorsanız kuyruğunuz yok

Kuyruk kurmak queue:work çalıştırmak değil. Başarısız işi kimse görmüyorsa kuyruk bir sistem değil, verinin sessizce kaybolduğu bir kuyudur.

failed_jobs tablosuna en son ne zaman baktınız.

Sessiz başarısızlık

Kuyruk işi patladığında kullanıcı bir şey görmüyor. HTTP isteği çoktan 200 dönmüş. Log dosyasında bir satır var ama kimse log dosyası okumuyor.

İş failed_jobs tablosuna düşüyor ve orada duruyor. Haftalarca.

Bunu fark ettiğiniz an genelde şudur: müşteri “üç haftadır fatura gelmiyor” diyor.

Önce tabloyu kur

Yoksa iş kayboluyor, tabloya bile düşmüyor.

php artisan make:queue-failed-table
php artisan migrate

config/queue.php içinde sürücünün database olduğundan emin olun. null ise başarısız işler hiçbir yere yazılmıyor.

Deneme sayısını açıkça yaz

Varsayılan --tries=1. Yani ilk hatada iş ölüyor. Geçici bir ağ hatası kalıcı veri kaybına dönüşüyor.

class SyncOrderToErp implements ShouldQueue
{
    public int $tries = 5;
    public int $timeout = 120;

    public function backoff(): array
    {
        return [10, 30, 60, 300];
    }
}

backoff bir dizi döndürüyor: ilk tekrar 10 saniye sonra, ikincisi 30, üçüncüsü 60. Sabit bekleme yerine bunu kullanın. Karşı taraf yükdeyse art arda beş kez vurmak durumu kötüleştiriyor.

Her hata tekrar denenmemeli

Beş kez denemek 500 hatası için doğru. 422 için yanlış.

Doğrulama hatası tekrar denendiğinde yine doğrulama hatası verir. Beş kez denemek sadece beş kat gürültü üretiyor.

public function handle(): void
{
    $response = $this->client->push($this->order);

    if ($response->status() === 422) {
        $this->fail(new InvalidOrderPayload($response->body()));
        return;
    }

    $response->throw();
}

fail() işi doğrudan failed_jobs tablosuna atıyor, tekrar denemiyor.

Zaman aşımı ile deneme sayısını birlikte düşünün

timeout bir denemenin süresi, tries deneme sayısı. İkisinin çarpımı işin en kötü durumda ne kadar süreceğidir.

Kuyruk sürücüsünde bir de görünmezlik süresi var. İş timeout süresinden uzun sürerse kuyruk onu kaybolmuş sayıp başka bir worker’a veriyor. Aynı iş iki kez çalışıyor.

retry_after değeri timeout değerinden büyük olmalı:

// config/queue.php
'database' => [
    'retry_after' => 180, // job timeout 120 ise bundan büyük
],

Bu ikisini ters kurmak, “iş neden iki kez çalıştı” sorusunun en sık cevabı.

Bildirim kurun

Asıl mesele bu. Tablo dolduğunda birinin haberi olmalı.

// AppServiceProvider::boot()
Queue::failing(function (JobFailed $event) {
    Log::channel('slack')->error('Kuyruk işi başarısız', [
        'job'       => $event->job->resolveName(),
        'exception' => $event->exception->getMessage(),
    ]);
});

Slack yoksa e-posta. E-posta da yoksa günde bir kez failed_jobs sayısını kontrol eden bir cron. Hangisi olursa olsun, tabloyu elle açmak bir izleme yöntemi değil.

Temizlik

Başarısız işler kendiliğinden silinmiyor.

php artisan queue:failed          # listele
php artisan queue:retry all       # hepsini tekrar dene
php artisan queue:flush --hours=168  # bir haftadan eskiyi sil

Son komutu zamanlanmış göreve ekleyin. Tablo yüz binlik satıra çıktığında sorgular yavaşlıyor.

Özet

Tabloyu kur. tries ve backoff yaz. Kalıcı hatada fail() çağır. retry_after değerini timeout üstünde tut. Başarısızlıkta bildirim gönder.

Beşinci madde olmadan diğer dördü işe yaramıyor.


Bu yazıyı paylaş:

Önceki Yazı
Shopify Admin API'de sayfalama ve maliyet
Sonraki Yazı
Docker imajınız neden 1,2 GB