Restart worker queue di Laravel bisa memicu job ganda, cache stale, dan race condition jika tidak ditangani secara sistematis. Artikel ini langsung menyajikan langkah operasional untuk memastikan konsistensi queue dan cache, mulai dari pengaturan respawn worker hingga monitoring detail error.
Mengapa Restart Worker Menyebabkan Ketidakkonsistenan Queue & Cache
Worker yang restart mendadak (misalnya karena deployment atau pemantauan) dapat memicu job yang sedang berjalan dianggap gagal, lalu dimasukkan ulang ke queue saat queue:work dijalankan kembali. Jika job sudah mengubah cache atau state secara parsial, hasilnya bisa tidak sinkron dengan data terakhir. Selain itu, cache-versioning dan lock Redis yang tidak sempurna membuat worker baru membaca nilai lama atau bangun ulang state yang sedang di-update.
Strategi Respawn Worker Terukur
Ambil pendekatan controlled rolling restart pekerja:
- Gunakan Supervisor atau systemd dengan konfigurasi graceful shutdown. Supervisor bisa mengatur
stopwaitsecscukup untuk menyelesaikan job aktif lalu memulai ulang worker satu per satu. - Script rolling deploy mengaktifkan
php artisan queue:restartsehingga worker saat ini menyelesaikan job sebelum exit. Setelah restart dipicu, jalankan script yang menyusuri worker target satu per satu, lalu tunggu mereka kembali online sebelum lanjut ke server berikutnya. - Deteksi job stuck melalui
php artisan queue:faileddan automatic retry yang sudah idempotent (lihat bagian berikut). Hindari restart massal tanpa observability, karena worker baru bisa mulai memproses job lama tanpa context.
Contoh snippet sederhana untuk respawn worker dengan lock file:
for host in backend-1 backend-2; do
ssh $host 'php /var/www/artisan queue:restart'
ssh $host 'supervisorctl restart laravel-worker'
sleep 15
done
Dengan jeda, Anda memberi waktu worker menyelesaikan job di-cache sekaligus mencegah spike beban.
Idempotensi Job & Sinkronisasi Status
Job yang dijalankan berkali-kali wajib idempotent. Tambahkan kolom seperti job_uuid pada tabel utama untuk menghindari side effect jika job di-retry:
public function handle()
{
$jobId = $this->job->uuid();
$processed = ProcessedJob::firstOrCreate(['job_id' => $jobId]);
if ($processed->wasRecentlyCreated) {
// proses utama, misalnya update status order dan cache
}
}
Pastikan pemrosesan utama berada dalam transaksi database atau ditandai dengan flag, sehingga job yang gagal tidak meninggalkan setengah perubahan. Setelah sisi cache diperbarui, catat timestamp atau versi untuk deteksi stale.
Cache Versioning & Lock Redis untuk Menghindari Race Condition
Gunakan cache versioning untuk mengetahui apakah data sudah ter-update setelah restart worker. Salah satu pendekatan sederhana:
$versionKey = 'orders:' . $order->id . ':version';
Cache::increment($versionKey);
Cache::put('order:' . $order->id, $payload, now()->addMinutes(10));
Worker yang membaca cache harus memeriksa versi yang tersimpan di database. Jika versi mismatch, worker menolak hasil cache dan memuat ulang dari sumber utama.
Untuk locking Redis, jangan hanya bergantung pada Cache::lock() tanpa timeout eksplisit. Pola yang aman:
$lock = Cache::lock('order:' . $order->id . ':lock', 30);
if ($lock->get()) {
try {
// operasi sensitif
} finally {
$lock->release();
}
} else {
// fallback: tunggu atau retry nanti
}
Gunakan retry count terbatas agar worker tidak menunggu tanpa batas, dan selalu perform release di blok finally. Jika worker restart saat lock masih aktif, lock otomatis kedaluwarsa setelah timeout, sehingga tidak menyebabkan deadlock.
Monitoring & Respon terhadap Error Queue
Setelah konsistensi dijaga, pastikan observability:
- Log berlapis dari job yang gagal, termasuk job_id, host, timestamp, dan alasan retry. Gunakan Monolog atau observer untuk menyertakan context dan trace.
- Gunakan Horizon atau Queue Monitor untuk melihat job yang terjebak dalam state processing. Alert ketika
pending > thresholdatau ketika percobaan melebihi limit. - Automasi retry terbatas dengan
backoffdantries. Jika job tetap gagal, drop ke tablefailed_jobsuntuk ditangani manual.
Jika restart worker menyebabkan lonjakan error, identifikasi job terkait lewat php artisan queue:failed --id=xxx lalu telusuri cache atau basis data yang belum konsisten.
Kesimpulan
Dengan prosedur respawn worker yang terukur, job idempotent, cache versioning, serta monitoring error queue, tim backend Laravel dapat menjaga konsistensi saat worker restart tanpa mengorbankan throughput. Fokus pada observabilitas, locking yang aman, dan dokumentasi prosedur recovery agar tim operasional bisa merespons cepat ketika gangguan terjadi.
Komentar
0 komentar
Masuk ke akun kamu untuk ikut berkomentar.
Belum ada komentar
Jadilah yang pertama ikut berdiskusi!