Ketika worker Laravel tersendat, backlog job bertambah sementara cache bisa kehilangan konsistensi dan lock menyumbat proses lain. Artikel ini langsung membahas cara mendiagnosis kasus tersebut, memperbaiki konfigurasi queue/cache, serta menambahkan strategi locking dan observability agar sistem kembali stabil.

Mendiagnosis Worker Tersendat dan Dampaknya

Masalah umum muncul ketika queue worker berhenti, retry tak terkendali terjadi, atau job masuk ke status failed karena timeout. Langkah diagnostik yang praktis adalah:

  • Jalankan php artisan queue:failed untuk melihat job yang sudah gagal dan isi error message agar tahu apakah timeout atau exception terjadi.
  • Periksa panjang antrian dengan driver yang digunakan. Untuk Redis, periksa key job dengan redis-cli LLEN queues:default.
  • Amati log worker (biasanya lewat Supervisor atau systemd) untuk melihat apakah ada stack trace repetitif atau worker timeout.
  • Pastikan tidak ada job yang menunggu lock/koneksi eksternal; job yang memanggil API eksternal panjang tanpa >timeout bisa membuat worker stuck.

Jika retry tak terkendali, cek nilai retry_after dan pastikan job tidak menyala lagi sebelum selesai benar-benar selesai. Untuk driver Redis, block_for juga memengaruhi bagaimana worker memanggil job berikutnya.

Menstabilkan Queue dan Cache

Konfigurasi Queue Driver yang Tahan Gangguan

Gunakan konfigurasi queue di config/queue.php yang menjamin job tidak terlupakan ketika worker mati:

'redis' => [
    'driver' => 'redis',
    'connection' => 'default',
    'queue' => env('REDIS_QUEUE', 'default'),
    'retry_after' => 90,
    'block_for' => 3,
],

Setting retry_after harus lebih besar dari waktu eksekusi job paling lama. block_for membantu worker menunggu job baru sebelum polling lagi, mengurangi tekanan pada Redis saat tidak ada job.

Cache Store yang Konsisten

Pilih cache store yang mendukung atomic operations, seperti Redis atau Memcached. Di config/cache.php, pastikan koneksi diarahkan ke instance yang sama dengan queue:

'redis' => [
    'driver' => 'redis',
    'connection' => 'cache',
],

Gunakan cache untuk menyimpan status job penting (misal: flag bahwa suatu batch sudah berjalan) dan bersihkan flag itu di akhir job atau saat terjadi exception. Pastikan job selalu menghapus flag di blok finally untuk mencegah deadlock cache.

Strategi Lock dan Pencegahan Deadlock

Pada job yang harus berjalan satu-satu (misal migrasi data), manfaatkan Redis lock dari Cache::lock. Contohnya:

use Illuminate\Support\Facades\Cache;

$lock = Cache::lock('process-batch', 120);

if ($lock->get()) {
    try {
        // jalankan job kritikal
    } finally {
        $lock->release();
    }
} else {
    // log atau requeue karena lock sedang digunakan
}

Durasi lock harus cukup untuk menyelesaikan job. Jika job bisa gagal dan butuh retry, gunakan block(10) untuk menunggu lock sebelum memutuskan fail. Hindari mengunci terlalu lama agar worker lain tidak menunggu selamanya.

Untuk job yang mengandalkan cache store biasa, implementasikan retry dengan backoff kecil dan pastikan cache store mendukung operasi atomic seperti add atau setnx.

Observability dan Alert Dasar

Observability sederhana sudah cukup untuk mencegah backlog makin parah. Terapkan:

  • Metrics Queue Length: Kirim nilai dari Redis LLEN ke dashboard Prometheus/Grafana atau cukup catat dengan php artisan queue:work --tries=1 dan parsing log.
  • Alert Failed Job: Tambah listener pada Illuminate\Queue\Events\JobFailed untuk mengirim notifikasi Slack/Email ketika job penting gagal.
  • Supervisor Restart: Gunakan Supervisor dengan konfigurasi seperti ini untuk otomatis restart worker jika berhenti:
    [program:laravel-worker]
    command=php /var/www/artisan queue:work redis --sleep=3 --tries=3
    numprocs=1
    autostart=true
    autorestart=true
    redirect_stderr=true
    stdout_logfile=/var/www/storage/logs/worker.log
    

Untuk tambahan, buat endpoint health check yang memeriksa koneksi Redis dan database. Monitoring sederhana ini memungkinkan deteksi dini saat worker sudah tertinggal job.

Ringkasan dan Tindakan Cepat

Ketika worker tersendat, diagnosis awal melalui log, job failed, dan status Redis adalah langkah paling cepat. Setelah itu, stabilkan konfigurasi queue/cache, pastikan job kritikal dilindungi lock, serta tambahkan observability sederhana agar tim bisa bereaksi sebelum backlog menjadi kritis. Implementasi praktis yang konsisten mampu menjaga sistem queue Laravel tetap handal meskipun beban tinggi.