Ketika job queue dalam CodeIgniter 4 memasuki status retry berulang, deadlock Redis bisa muncul karena lock yang tidak dilepas dan retry yang menumpuk. Artikel ini langsung menjelaskan gejala yang muncul, instrumen observasi seperti log worker serta redis-cli, akar masalah yang umum terjadi, dan langkah konkret untuk memperbaikinya agar queue tetap stabil.

Gejala Deadlock Redis pada Retry Queue

Pertama-tama, identifikasi gejala: worker berhenti memproses item baru, backlog queue terus bertambah, dan setiap retry job memegang lock lebih lama dari seharusnya. Worker menulis log seperti "Job failed, retrying" tanpa ada selingan pemrosesan lain, sementara Redis menunjukkan lock key dengan TTL yang tidak berkurang.

Kesimpulannya, deadlock terlihat dari pemrosesan job yang tidak maju dan lock Redis yang tidak pernah dilepaskan. Langsung lanjut ke pengamatan log dan Redis untuk membuktikan.

Observasi untuk Menentukan Ruang Lingkup

1. Log Worker dan Timing Retry

Periksa file log worker (biasanya di writable/logs) untuk pola seperti JobClass: attempt X tanpa job selesai. Pastikan timestamp worker memperlihatkan job baru tidak dimulai karena worker menunggu release lock yang sudah kadaluwarsa.

2. Redis Monitoring

Gunakan redis-cli untuk memeriksa status lock dan pending queue.

redis-cli> MONITOR
redis-cli> TTL job:12345:lock
redis-cli> KEYS job:*:lock

Perintah MONITOR memberi visibilitas terhadap command yang dijalankan worker. TTL menunjukkan apakah lock otomatis akan dilepaskan. Jika TTL tetap tinggi dan tidak menurun, berarti ada job yang memegang lock tapi tidak selesai.

3. Statistik Queue

Gunakan metode queue CodeIgniter untuk mengetahui jumlah retry per job dan job terakhir yang dilakukan. Kombinasikan dengan php spark queue:work untuk mempersempit segmen yang bermasalah.

Penelusuran Root Cause

Konflik Lock karena Retry Serentak

Deadlock terjadi saat dua atau lebih worker mencoba memproses job yang sama karena lock tidak segera dilepas. Jika retry dilakukan tanpa backoff, job bisa diambil ulang sebelum lock lama habis, menghasilkan loop. Dari log ditemukan pola retry setelah 0 detik.

Timeout Worker yang Terlalu Pendek

Worker yang timeout cepat akan memaksa job masuk retry, namun lock yang sudah terpasang tidak sempat dihapus. Akibatnya, job berikutnya mendapati lock masih aktif dan menunggu tanpa batas. Pastikan timeout worker lebih panjang dari waktu pemrosesan job tipikal.

Urutan Retry yang Tidak Teratur

Jika job menulis status retrying tanpa menghapus lock atau tidak memeriksa status sebelumnya, job berikutnya bisa memegang lock yang lama. Observasi log membuktikan job yang sama dieksekusi terus-menerus dengan ID lock yang identik.

Tindakan Perbaikan yang Terbukti

1. Konfigurasi Backoff pada Retry

Terapkan interval retry bertahap sehingga lock punya waktu kadaluwarsa sebelum job baru dijalankan. Dalam CodeIgniter 4, setelan backoff bisa dilakukan di file konfigurasi queue:

public $default = [
    'driver' => 'redis',
    'retryDelay' => 5000,
    'maxAttempts' => 5,
    'backoff' => [5000, 10000, 20000],
    'timeout' => 60,
];

Backoff array membuat job menunggu lebih lama setiap kali retry, mengurangi peluang retry serentak.

2. Lock Tersebar (Distributed Lock)

Alih-alih mengandalkan simple key, gunakan