Ketika job queue Laravel tiba-tiba mengalami delay meski CPU worker kosong, penyebab paling umum adalah kondisi cache yang tidak konsisten. Dalam kasus ini, gejala tersebut terbukti berasal dari fragmentasi cache akibat cache tag yang tidak sinkron dengan eviction policy Redis. Artikel ini menjelaskan proses debugging: dari gejala log queue worker dan metrik Redis sampai solusi teknis seperti penyetelan cache tag, isolasi namespace, revisi kebijakan eviction, dan automasi functional test.
Gejala dan Diagnosa Awal
Langkah pertama adalah menuliskan apa yang terlihat. Pada queue worker Laravel (`php artisan queue:work`), log menunjukkan "Processing job" dengan delay beberapa detik bahkan ketika tidak ada backlog besar. Delay ini persisten pada job yang sebelumnya selesai cepat.
Log Queue Worker
Log menunjukkan interval waktu antara job yang dijalankan berfluktuasi tinggi. Contohnya, job pertama selesai dalam 200 ms, job kedua menunggu 6 detik meski tidak ada pekerjaan lain. Tidak ada exception, namun worker mengindikasikan job baru tidak diambil segera.
Reproduksi di Staging dan Metrik Redis
Di environment staging, kami memanggil queue worker dengan dataset yang sama seperti produksi. Metrik Redis menunjukkan keys dengan tag yang kian banyak namun TTL tidak konsisten. Redis INFO mengungkap beberapa perintah EVICT tidak berjalan karena fragmentasi internal, sementara rate konversi cache tag ke key naik drastis.
Gabungan gejala ini mengarah pada hipotesis fragmentasi cache: Laravel menyimpan data berlabel cache tag untuk job deserialized, namun eviction policy Redis (LRU default) menyingkirkan key-tag pair tanpa menghapus entri tag yang terkait. Akibatnya, worker menunggu cache tag cleanup, memperlambat job queue.
Analisis Akar Masalah: Cache Fragmentasi dan Cache Tag
Laravel job queue menggunakan cache untuk menyimpan job metadata, terutama saat menggunakan cache-based queue driver. Ketika job dijalankan dan mengupdate cache tag, Laravel menyisipkan key dengan format kombinasi tag + key. Jika ada mismatch antara tag yang digunakan di application logic dan yang disimpan di Redis (misalnya cache tag berbeda setelah deployment), maka tag lama tetap menumpuk.
Fragmentasi muncul ketika laravel cache tag tidak sinkron: beberapa job menyimpan dengan tag jobs:critical sementara job lain menggunakan tag jobs:critical_v2. Redis memanggil eviction untuk key lama, tetapi tag yang tersisa membuat collection menjadi besar sehingga worker memerlukan waktu untuk mengecek keabsahan tag. Redis key spread juga menghambat command pipeline, memperpanjang delay.
Solusi Teknis
Penyetelan Cache Tags dan Namespace
Solusi pertama adalah konsistensi tag. Gunakan helper yang merujuk ke satu definisi tag dan hindari string literal di banyak tempat. Buat wrapper cache seperti:
class JobCacheManager
{
public static function rememberJob(string $tag, string $key, Closure $callback): mixed
{
return Cache::tags(['jobs', $tag])->remember($key, now()->addMinutes(5), $callback);
}
}
Dengan wrapper, Anda dapat mengatur namespace untuk setiap job dan mudah memperbarui tag tanpa tersebar di seluruh kode.
Isolasi Namespace Cache
Jika cache digunakan untuk tujuan lain, pastikan job queue menggunakan namespace sendiri agar eviction policy tidak memengaruhi data lain. Di config/cache.php, set environment prefix berbeda:
'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_jobqueue'),
Dengan prefix terisolasi, key job tidak bercampur dengan cache lain; Redis eviction bisa fokus jika namespace dipisahkan ke database Redis berbeda ketika perlu.
Revisi Kebijakan Eviction
Apabila Redis digunakan untuk banyak namespace, pertimbangkan mengubah policy dari default volatile-lru ke allkeys-lru dan pastikan TTL job tidak terlalu panjang. Penyesuaian ini menghindari fragmentasi dari cache tag yang tidak pernah dipanggil ulang.
Automasi Functional Test
Tambahkan functional test yang memicu job dengan tag tertentu dan memverifikasi waktu respons queue worker tidak melampaui ambang batas. Gunakan test yang menyetel cache Redis ke keadaan awal (flush pada namespace job) sebelum difungsikan, supaya regression fragmentasi cepat terdeteksi.
Tambahkan skrip CI yang memanggil queue worker dengan load simulasi, lalu periksa log dan metrik latency. Integrasi testing ini membantu menghindari penundaan job akibat cache fragmentation di masa mendatang.
Observability dan Pencegahan Ulang
Rekomendasi monitoring untuk mendeteksi ulang:
- Track latency job queue dengan histogram (misalnya melalui Prometheus) dan set alert jika median naik > 500 ms.
- Kumpulkan metrik Redis seperti keyspace hits/misses, evicted_keys, memory_fragmentation_ratio, serta jumlah cache tag per namespace.
- Gunakan Redis latency monitor (LATENCY DOCTOR) untuk mencatat spike setelah release deployment yang mengubah tag.
- Aktifkan logging detail pada cache tag operations agar Anda tahu tag mana yang tidak pernah dihapus.
Dengan observability yang tepat, Anda dapat melihat pola fragmentasi sebelum job queue mengalami delay signifikan.
Kesimpulan
Delay queue worker di Laravel bisa jadi disebabkan oleh cache fragmentation, terutama saat cache tag tidak sinkron dan eviction policy redis tidak mendukung. Diagnosa real di staging penting untuk melihat log worker, metrik Redis, dan mengidentifikasi namespace bermasalah. Solusi meliputi konsistensi cache tag, isolasi namespace, penyetelan eviction, dan automasi functional test. Observability yang mencakup latency, Redis key metrics, dan cache tag logging membantu mencegah terulangnya masalah.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!