Laravel Queue Failed Jobs: Cara Retry dan Menangani Job yang Gagal
Laravel Queue memungkinkan aplikasi menjalankan pekerjaan di background tanpa membuat pengguna harus menunggu proses selesai. Contohnya adalah mengirim email, membuat laporan, memproses gambar, mengirim notifikasi, atau melakukan sinkronisasi data dengan API eksternal.
Namun, tidak semua Job selalu berhasil.
Sebuah Job dapat gagal karena API sedang down, koneksi database bermasalah, Redis tidak dapat diakses, data yang dibutuhkan tidak ditemukan, terjadi exception di dalam kode, atau waktu eksekusi Job melebihi batas yang ditentukan.
Laravel menyediakan fitur Failed Jobs untuk menyimpan informasi tentang Job yang gagal sehingga developer dapat mengetahui penyebabnya dan menjalankan Job tersebut kembali.
Pada artikel ini kita akan membahas:
- Apa itu Laravel Failed Jobs
- Mengapa Job bisa masuk ke
failed_jobs - Cara melihat Failed Jobs
- Cara membaca error Job
- Cara retry satu Job
- Cara retry semua Job
- Cara menghapus Failed Job
- Mengatur jumlah percobaan dengan
tries - Mengatur jeda retry dengan
backoff - Menggunakan exponential backoff
- Menggunakan
retryUntil - Menangani kegagalan dengan method
failed() - Perbedaan retry Job dan menjalankan Job baru
- Cara menangani Failed Jobs di production
- Troubleshooting Job yang terus gagal setelah di-retry
Apa Itu Laravel Failed Jobs?
Failed Job adalah Job yang sudah dicoba diproses oleh Laravel tetapi akhirnya dianggap gagal setelah mencapai batas percobaan atau mengalami kondisi yang menyebabkan Job gagal.
Laravel dapat menyimpan informasi Failed Job ke dalam penyimpanan failed-job yang dikonfigurasi. Pada konfigurasi database, informasi tersebut disimpan di tabel:
failed_jobs
Tabel ini membantu developer melakukan troubleshooting tanpa harus kehilangan informasi mengenai Job yang gagal.
Laravel menyediakan command Artisan untuk melihat Failed Jobs:
php artisan queue:failed
Command tersebut menampilkan informasi seperti ID Job, connection, queue, dan waktu ketika Job gagal.
Mengapa Laravel Queue Job Bisa Gagal?
Sebelum melakukan retry, hal terpenting adalah memahami mengapa Job gagal.
Beberapa penyebab yang umum antara lain:
1. Exception di dalam Job
Contohnya:
public function handle(): void
{
$user = User::findOrFail($this->userId);
// ...
}
Jika user tidak ditemukan, Laravel dapat melempar exception dan Job gagal.
2. API eksternal tidak tersedia
Misalnya Job melakukan request ke:
https://api.example.com
Jika API sedang down atau timeout, Job dapat gagal.
3. Database bermasalah
Contohnya:
SQLSTATE[HY000]
Connection refused
Too many connections
4. Redis bermasalah
Jika Redis digunakan sebagai queue backend, koneksi Redis yang gagal dapat menyebabkan masalah pada proses Queue.
5. Timeout
Job yang membutuhkan waktu terlalu lama dapat melewati batas timeout worker.
6. Jumlah percobaan sudah habis
Sebuah Job dapat dicoba beberapa kali. Jika seluruh percobaan gagal, Laravel akan menganggap Job tersebut gagal.
Laravel memungkinkan jumlah percobaan ditentukan melalui --tries pada worker atau konfigurasi pada Job itu sendiri.
Cara Melihat Laravel Failed Jobs
Untuk melihat daftar Failed Jobs, jalankan:
php artisan queue:failed
Contoh output dapat terlihat seperti:
+--------------------------------------+------------+---------+---------------------+
| ID | Connection | Queue | Failed At |
+--------------------------------------+------------+---------+---------------------+
| 8d8c... | redis | default | 2026-08-16 10:20:12 |
| 92ab... | redis | emails | 2026-08-16 10:21:45 |
+--------------------------------------+------------+---------+---------------------+
ID tersebut penting karena dapat digunakan untuk melakukan retry terhadap Job tertentu.
Laravel mendokumentasikan bahwa queue:failed menampilkan ID yang kemudian dapat digunakan sebagai argument untuk queue:retry.
Cara Mengetahui Penyebab Failed Job
Melihat daftar Failed Jobs saja belum cukup.
Anda perlu mengetahui exception atau error yang menyebabkan Job gagal.
Salah satu tempat pertama yang perlu diperiksa adalah log Laravel:
tail -f storage/logs/laravel.log
Kemudian perhatikan error yang muncul ketika Job dijalankan.
Contohnya:
SQLSTATE[HY000] [2002] Connection refused
atau:
RedisException: Connection refused
atau:
Allowed memory size exhausted
atau:
Maximum execution time exceeded
Jangan langsung melakukan retry berkali-kali sebelum memahami error tersebut.
Jika penyebabnya belum diperbaiki, retry hanya akan membuat Job gagal lagi.
Cara Retry Failed Job di Laravel
Setelah penyebab error diperbaiki, Anda dapat menjalankan kembali Failed Job.
Misalnya hasil:
php artisan queue:failed
menampilkan ID:
8d8c1234-xxxx-xxxx-xxxx-123456789abc
Jalankan:
php artisan queue:retry 8d8c1234-xxxx-xxxx-xxxx-123456789abc
Laravel akan memasukkan kembali Job tersebut ke queue untuk diproses oleh worker.
Setelah itu pastikan worker sedang berjalan:
php artisan queue:work
Jika menggunakan Redis:
php artisan queue:work redis
Retry Beberapa Failed Job Sekaligus
Anda juga dapat memberikan beberapa ID sekaligus.
Contoh:
php artisan queue:retry ID_1 ID_2 ID_3
Misalnya:
php artisan queue:retry \
8d8c1234-xxxx-xxxx-xxxx-123456789abc \
92ab1234-xxxx-xxxx-xxxx-987654321abc
Cara ini berguna ketika Anda sudah memperbaiki satu masalah yang menyebabkan beberapa Job gagal.
Cara Retry Semua Failed Jobs
Jika Anda yakin seluruh Failed Jobs aman untuk dijalankan kembali, gunakan:
php artisan queue:retry all
Laravel menyediakan all untuk me-retry seluruh Failed Jobs yang tersimpan.
Namun, jangan sembarangan menjalankan command ini di production.
Bayangkan ada 10.000 Job yang gagal karena API eksternal mengalami gangguan.
Jika API tersebut belum pulih kemudian Anda menjalankan:
php artisan queue:retry all
semua Job dapat kembali diproses dan gagal lagi.
Bahkan jika API sudah pulih, retry massal dapat menyebabkan lonjakan request.
Karena itu, lebih baik:
- identifikasi penyebab,
- perbaiki masalah,
- pastikan service tujuan sudah normal,
- retry Job yang relevan,
- monitor hasilnya.
Retry Failed Jobs pada Queue Tertentu
Jika aplikasi memiliki beberapa queue, misalnya:
high
default
emails
reports
Anda dapat melakukan retry berdasarkan queue tertentu.
Contoh:
php artisan queue:retry --queue=emails
Ini berguna ketika Anda hanya ingin mengembalikan Failed Jobs yang berasal dari queue tertentu. Laravel menyediakan opsi --queue pada queue:retry.
Menghapus Failed Job
Tidak semua Failed Job harus di-retry.
Misalnya Job sudah tidak relevan karena:
- data sudah dihapus,
- user sudah membatalkan transaksi,
- proses sudah dilakukan secara manual,
- atau Job tersebut berasal dari testing.
Untuk menghapus satu Failed Job:
php artisan queue:forget JOB_ID
Contoh:
php artisan queue:forget 8d8c1234-xxxx-xxxx-xxxx-123456789abc
Laravel juga menyediakan:
php artisan queue:flush
untuk menghapus seluruh Failed Jobs.
Hati-hati dengan queue:flush
Command:
php artisan queue:flush
menghapus seluruh record Failed Jobs.
Jangan menjalankannya hanya karena tabel failed_jobs terlihat banyak.
Record tersebut bisa sangat berguna untuk debugging dan audit masalah Queue.
Laravel juga menyediakan opsi --hours untuk membatasi record yang dihapus berdasarkan usia kegagalannya.
Contoh:
php artisan queue:flush --hours=48
Mengatur Jumlah Retry dengan --tries
Secara default, jumlah percobaan Job dapat dikontrol dari worker.
Contoh:
php artisan queue:work redis --tries=3
Artinya worker mengizinkan Job dicoba sampai batas yang ditentukan tersebut sebelum dianggap gagal.
Laravel juga memungkinkan jumlah percobaan ditentukan langsung pada Job. Jika Job memiliki konfigurasi attempts sendiri, konfigurasi tersebut dapat mengambil precedence dibanding nilai --tries dari worker.
Mengatur tries pada Job
Contoh Job:
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class SendInvoiceEmail implements ShouldQueue
{
use Queueable;
public $tries = 3;
public function handle(): void
{
// Proses pengiriman email
}
}
Dengan konfigurasi tersebut, Job mempunyai batas percobaan sendiri.
Pendekatan ini berguna ketika setiap jenis Job membutuhkan strategi retry yang berbeda.
Misalnya:
SendEmailJob → 3 attempts
SyncPaymentJob → 5 attempts
GenerateReportJob → 2 attempts
Dengan begitu Anda tidak perlu memberikan konfigurasi retry yang sama kepada semua Job.
Menggunakan retryUntil
Selain jumlah percobaan, Laravel memungkinkan Anda menentukan batas waktu sampai kapan Job boleh dicoba kembali.
Contoh:
use DateTime;
public function retryUntil(): DateTime
{
return now()->plus(minutes: 30);
}
Artinya Job dapat terus dicoba dalam jangka waktu tersebut, sesuai mekanisme retry yang digunakan.
Pendekatan ini berguna ketika Anda lebih peduli pada batas waktu daripada jumlah percobaan.
Misalnya Anda memiliki Job untuk melakukan sinkronisasi pembayaran.
Daripada mengatakan:
coba maksimal 5 kali
Anda dapat menggunakan pendekatan:
coba selama maksimal 30 menit
Laravel memberikan precedence kepada retryUntil() jika retryUntil dan tries sama-sama didefinisikan.
Mengatur Jeda Retry dengan backoff
Tidak semua error sebaiknya langsung dicoba kembali.
Misalnya API eksternal sedang mengalami gangguan.
Jika Job langsung retry tanpa jeda:
Request gagal
↓
Retry
↓
Gagal
↓
Retry
↓
Gagal
aplikasi justru dapat memberikan beban tambahan pada service yang sedang bermasalah.
Laravel menyediakan backoff untuk menentukan waktu tunggu sebelum retry.
Contoh pada worker:
php artisan queue:work redis --tries=3 --backoff=5
Artinya worker menunggu sebelum mencoba kembali Job yang mengalami exception. Laravel mendukung pengaturan backoff pada worker maupun Job.
Mengatur backoff pada Job
Anda juga dapat menentukan backoff langsung pada Job.
Contoh:
public $backoff = 5;
Full example:
<?php
namespace App\Jobs;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class SendInvoiceEmail implements ShouldQueue
{
use Queueable;
public $tries = 3;
public $backoff = 5;
public function handle(): void
{
// Kirim email
}
}
Sekarang Job memiliki:
Maximum attempts: 3
Retry delay: 5 seconds
Exponential Backoff pada Laravel Queue
Untuk API eksternal atau service yang kemungkinan sedang overload, exponential backoff sering lebih masuk akal daripada retry dengan interval tetap.
Contohnya:
public function backoff(): array
{
return [1, 5, 10];
}
Dengan konfigurasi tersebut, retry dapat menggunakan pola:
Attempt 1
↓
1 detik
↓
Attempt 2
↓
5 detik
↓
Attempt 3
↓
10 detik
Laravel mendukung array pada method backoff() untuk menentukan beberapa nilai delay retry. Jika jumlah percobaan lebih banyak daripada jumlah nilai dalam array, nilai terakhir digunakan untuk percobaan berikutnya.
Contoh:
public function backoff(): array
{
return [1, 5, 10];
}
Ini lebih baik daripada retry tanpa jeda untuk banyak jenis kegagalan sementara.
Contoh Job dengan Retry yang Lebih Lengkap
Berikut contoh sederhana Job yang mempunyai batas retry, backoff, dan handler ketika seluruh percobaan gagal:
<?php
namespace App\Jobs;
use Throwable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class SyncOrderToApi implements ShouldQueue
{
use Queueable;
public $tries = 3;
public function backoff(): array
{
return [5, 15, 30];
}
public function handle(): void
{
// Kirim data order ke API eksternal
}
public function failed(?Throwable $exception): void
{
// Jalankan ketika Job akhirnya gagal
}
}
Strateginya menjadi:
Attempt 1
↓ gagal
tunggu 5 detik
↓
Attempt 2
↓ gagal
tunggu 15 detik
↓
Attempt 3
↓ gagal
failed()
Menangani Job yang Benar-Benar Gagal dengan failed()
Laravel menyediakan method failed() pada Job untuk menangani kondisi ketika Job akhirnya gagal.
Contoh:
public function failed(?Throwable $exception): void
{
Log::error('Sync order gagal', [
'order_id' => $this->orderId,
'error' => $exception?->getMessage(),
]);
}
Method ini dapat digunakan untuk:
- mencatat error,
- mengirim notifikasi,
- mengubah status database,
- memberi tahu administrator,
- atau melakukan cleanup tertentu.
Contoh yang lebih realistis:
public function failed(?Throwable $exception): void
{
Order::whereKey($this->orderId)->update([
'sync_status' => 'failed',
]);
Log::error('Order gagal disinkronisasi', [
'order_id' => $this->orderId,
'error' => $exception?->getMessage(),
]);
}
Dengan begitu aplikasi tidak hanya mengetahui bahwa Queue gagal, tetapi juga dapat memperbarui status bisnis yang berkaitan dengan Job.
Laravel mencatat bahwa instance Job baru dibuat sebelum method failed() dipanggil. Karena itu, perubahan property yang hanya terjadi selama handle() tidak boleh diasumsikan masih tersedia di failed(). Exception terakhir dapat diterima melalui parameter $exception.
Jangan Retry Semua Jenis Error
Ini bagian yang sering terlewat ketika membangun sistem Queue.
Tidak semua error cocok untuk retry.
Misalnya API sedang timeout:
Connection timeout
Retry mungkin masuk akal.
Tetapi jika errornya:
Invalid API key
retry berkali-kali tidak akan memperbaiki masalah.
Begitu juga:
User tidak ditemukan
atau:
Data sudah dihapus
Retry kemungkinan hanya akan menghasilkan error yang sama.
Secara sederhana, bedakan error menjadi:
| Jenis error | Retry? |
|---|---|
| API timeout | Ya |
| Redis sementara tidak tersedia | Ya |
| Database connection timeout | Ya |
| HTTP 429 Too Many Requests | Ya, dengan backoff |
| HTTP 500 dari API eksternal | Biasanya ya |
| API key salah | Tidak sebelum konfigurasi diperbaiki |
| Data tidak ditemukan | Biasanya tidak |
| Validation error permanen | Tidak |
| Bug pada kode | Tidak sebelum bug diperbaiki |
Strategi retry sebaiknya mengikuti karakter error, bukan sekadar menetapkan tries=10.
Retry vs Release: Apa Bedanya?
Laravel juga memungkinkan Job dilepas kembali ke queue menggunakan:
$this->release();
Anda juga dapat menentukan delay:
$this->release(10);
Artinya Job dikembalikan ke queue dan baru tersedia untuk diproses kembali setelah waktu yang ditentukan. Laravel mendukung delay menggunakan integer detik atau date instance.
Contoh:
public function handle(): void
{
if ($this->serviceIsTemporarilyUnavailable()) {
$this->release(30);
return;
}
// Lanjutkan proses
}
Pendekatan ini berguna ketika Anda mengetahui bahwa kondisi tersebut bersifat sementara dan Job sebaiknya dicoba lagi nanti.
Retry Failed Job Tidak Sama dengan Membuat Job Baru
Ini penting untuk dipahami.
Ketika Anda menjalankan:
php artisan queue:retry JOB_ID
Anda sedang mengembalikan Failed Job ke queue untuk dicoba kembali.
Sedangkan:
dispatch(new SyncOrderToApi($orderId));
membuat dan memasukkan Job baru ke queue.
Dalam aplikasi yang menangani pembayaran, order, atau transaksi, perbedaan ini sangat penting.
Jika Anda tidak hati-hati, Anda dapat memproses operasi yang sama lebih dari satu kali.
Waspadai Duplicate Processing
Bayangkan Job berikut:
public function handle(): void
{
$this->chargePayment();
throw new Exception('Something went wrong');
}
Bagaimana jika:
chargePayment()
sebenarnya berhasil, tetapi exception terjadi setelah pembayaran sukses?
Laravel menganggap Job gagal.
Kemudian Anda menjalankan:
php artisan queue:retry JOB_ID
Job diproses kembali.
Akibatnya:
Pembayaran pertama → sukses
Retry → pembayaran kedua → sukses
Anda berpotensi melakukan transaksi dua kali.
Karena itu, Job yang melakukan operasi penting harus dirancang agar idempotent atau aman ketika dijalankan lebih dari sekali.
Contohnya gunakan:
- unique transaction ID,
- idempotency key,
- pengecekan status sebelum melakukan operasi,
- database constraint,
- atau mekanisme deduplikasi.
Ini sangat penting untuk Job yang berkaitan dengan:
- pembayaran,
- invoice,
- pengiriman,
- stok,
- webhook,
- dan integrasi API eksternal.
Failed Jobs dengan Redis
Jika Anda menggunakan Redis sebagai Queue connection, proses Queue biasanya berjalan seperti:
Laravel
↓
Redis
↓
Queue Worker
↓
Job
Jika Job gagal berkali-kali sampai melewati batas percobaan, informasi Failed Job akan ditangani oleh mekanisme failed-job yang dikonfigurasi Laravel.
Contoh worker:
php artisan queue:work redis --tries=3
Kemudian periksa:
php artisan queue:failed
Untuk sistem Laravel + Redis + Supervisor, Anda juga perlu memastikan worker tetap berjalan setelah Job gagal.
Jika menggunakan Horizon, mekanisme monitoring dan pengelolaan queue berbeda karena Horizon memang dirancang untuk Redis queues. Laravel mendokumentasikan bahwa Horizon mengelola Redis queues.
Failed Jobs dengan Laravel Horizon
Jika aplikasi menggunakan Laravel Horizon, Anda dapat memonitor Queue melalui dashboard Horizon.
Horizon sangat berguna untuk melihat kondisi Queue secara lebih visual, termasuk Job yang mengalami masalah.
Namun, command yang digunakan untuk menghapus Failed Job perlu diperhatikan.
Untuk aplikasi yang menggunakan Horizon, Laravel merekomendasikan menggunakan:
php artisan horizon:forget JOB_ID
daripada:
php artisan queue:forget JOB_ID
ketika menghapus Failed Job yang dikelola oleh Horizon.
Ini menjadi salah satu alasan mengapa artikel tentang Failed Jobs sebaiknya dibaca bersama artikel tentang Laravel Horizon.
Apa yang Harus Dilakukan Setelah Job Gagal?
Gunakan alur berikut:
Job gagal
↓
Periksa queue:failed
↓
Cari error
↓
Periksa laravel.log
↓
Tentukan apakah error sementara/permanen
↓
Perbaiki penyebab
↓
Retry Job
↓
Monitor hasil
Jangan menggunakan pola:
Job gagal
↓
queue:retry all
↓
Job gagal lagi
↓
queue:retry all
Jika masalah utama belum diperbaiki, retry hanya mengulang masalah.
Contoh Troubleshooting Failed Job
Misalnya Anda memiliki Job:
class SendInvoiceEmail implements ShouldQueue
{
public $tries = 3;
public function handle(): void
{
Mail::to($this->email)->send(
new InvoiceMail($this->invoice)
);
}
}
Kemudian:
php artisan queue:failed
menampilkan:
Connection: redis
Queue: emails
Anda periksa log:
tail -f storage/logs/laravel.log
ternyata ditemukan:
Connection could not be established with SMTP server
Jangan langsung retry.
Periksa terlebih dahulu:
SMTP_HOST
SMTP_PORT
MAIL_USERNAME
MAIL_PASSWORD
Setelah konfigurasi SMTP diperbaiki, baru jalankan:
php artisan queue:retry JOB_ID
Kemudian monitor:
php artisan queue:failed
Jika Job sudah berhasil, record tersebut tidak lagi berada dalam daftar Failed Jobs.
Bagaimana Jika Job Terus Gagal Setelah Retry?
Jika Job tetap gagal setelah retry, jangan terus menjalankan:
php artisan queue:retry all
Cari pola errornya.
Jika error selalu sama
Contoh:
Class "App\Services\PaymentService" not found
Kemungkinan ada masalah pada kode atau deployment.
Jika error hanya kadang terjadi
Contoh:
Connection timed out
Kemungkinan masalahnya bersifat sementara.
Gunakan retry dengan backoff.
Jika error terjadi setelah waktu tertentu
Misalnya:
TimeoutExceededException
Periksa:
--timeout
retry_after
Laravel menjelaskan bahwa --timeout dan retry_after bekerja bersama. Nilai --timeout sebaiknya beberapa detik lebih pendek daripada retry_after agar worker dihentikan sebelum Job menjadi tersedia kembali untuk diproses. Jika timeout worker lebih panjang daripada retry_after, Job dapat berpotensi diproses dua kali.
Jangan Membuat tries Terlalu Besar
Contoh konfigurasi:
php artisan queue:work redis --tries=20
Tidak selalu berarti sistem lebih reliable.
Jika Job gagal karena bug:
Attempt 1 → gagal
Attempt 2 → gagal
Attempt 3 → gagal
...
Attempt 20 → gagal
Anda hanya membuang resource server.
Untuk error permanen, lebih baik:
Job gagal
↓
Catat error
↓
Perbaiki masalah
↓
Retry
Daripada:
Job gagal
↓
Retry 20x
Strategi Retry yang Lebih Aman
Untuk Job yang berinteraksi dengan API eksternal, Anda dapat menggunakan kombinasi:
public $tries = 5;
public function backoff(): array
{
return [5, 15, 30, 60];
}
Strateginya:
Attempt 1
↓ gagal
5 detik
↓
Attempt 2
↓ gagal
15 detik
↓
Attempt 3
↓ gagal
30 detik
↓
Attempt 4
↓ gagal
60 detik
↓
Attempt 5
Setelah semua percobaan gagal, Job masuk ke kondisi Failed Job.
Laravel mendukung pola backoff berbentuk array seperti ini untuk memberikan jeda berbeda pada setiap percobaan.
Monitoring Failed Jobs di Production
Untuk production, Failed Jobs sebaiknya tidak hanya menjadi tabel yang diperiksa ketika ada masalah.
Anda sebaiknya mempunyai mekanisme monitoring.
Minimal:
Queue Worker
↓
Failed Jobs
↓
Laravel Log
↓
Monitoring / Alert
Jika aplikasi menggunakan Horizon, manfaatkan dashboard untuk melihat aktivitas Queue.
Jika menggunakan Supervisor, pastikan worker berstatus:
sudo supervisorctl status
Dan untuk Laravel Queue:
php artisan queue:failed
Anda juga dapat menggabungkan monitoring tersebut dengan sistem logging atau notification yang digunakan aplikasi.
Bersihkan Failed Jobs Secara Berkala
Tabel failed_jobs dapat terus bertambah jika tidak pernah dibersihkan.
Untuk menghapus Failed Jobs lama, Laravel menyediakan:
php artisan queue:flush --hours=48
Perintah tersebut dapat digunakan untuk menghapus record Failed Jobs yang sudah berada di luar rentang waktu yang ditentukan.
Namun, sebelum menghapusnya, pertimbangkan apakah record tersebut masih diperlukan untuk:
- debugging,
- audit,
- investigasi incident,
- atau kebutuhan operasional.
Jangan menganggap semakin sedikit Failed Jobs berarti aplikasi semakin sehat.
Jumlah Failed Jobs yang tiba-tiba meningkat justru bisa menjadi sinyal adanya masalah.
Checklist Laravel Failed Jobs
Sebelum melakukan retry, periksa:
[ ] Sudah menjalankan php artisan queue:failed
[ ] Sudah mengetahui Job yang gagal
[ ] Sudah memeriksa error/log
[ ] Penyebab error sudah diperbaiki
[ ] API/database/Redis yang bermasalah sudah normal
[ ] Job aman untuk dijalankan ulang
[ ] Tidak berpotensi melakukan transaksi dua kali
[ ] Worker masih berjalan
[ ] Connection Queue sudah benar
[ ] Queue yang digunakan sudah benar
Setelah itu:
php artisan queue:retry JOB_ID
Kemudian monitor hasilnya.
Perintah Laravel Failed Jobs yang Perlu Diingat
Berikut command yang paling sering digunakan:
Melihat Failed Jobs
php artisan queue:failed
Retry satu Job
php artisan queue:retry JOB_ID
Retry beberapa Job
php artisan queue:retry ID_1 ID_2 ID_3
Retry semua Job
php artisan queue:retry all
Retry berdasarkan queue
php artisan queue:retry --queue=emails
Menghapus satu Failed Job
php artisan queue:forget JOB_ID
Menghapus semua Failed Jobs
php artisan queue:flush
Menghapus Failed Jobs yang lebih lama dari periode tertentu
php artisan queue:flush --hours=48
Untuk Horizon, gunakan:
php artisan horizon:forget JOB_ID
untuk menghapus Failed Job yang dikelola Horizon.
Kesimpulan
Laravel Failed Jobs bukan berarti sistem Queue Anda rusak.
Failed Job justru merupakan mekanisme penting untuk mengetahui bahwa sebuah Job sudah gagal diproses dan membutuhkan perhatian.
Alur yang paling aman adalah:
Job gagal
↓
queue:failed
↓
Cari penyebab
↓
Perbaiki error
↓
Pastikan Job aman diulang
↓
queue:retry JOB_ID
↓
Monitor
Untuk Job yang berkomunikasi dengan service eksternal, gunakan strategi retry yang sesuai. Anda dapat mengatur jumlah percobaan dengan tries, memberikan jeda menggunakan backoff, atau menggunakan retryUntil ketika batas waktu lebih relevan daripada jumlah percobaan. Laravel juga menyediakan method failed() untuk menjalankan penanganan khusus ketika Job benar-benar gagal.
Yang paling penting, jangan menganggap retry sebagai solusi untuk semua error.
Jika penyebabnya adalah bug permanen, API key salah, data tidak tersedia, atau masalah logika aplikasi, retry berkali-kali hanya akan mengulang kegagalan.
Dan untuk Job yang menangani pembayaran, stok, invoice, atau transaksi penting, pastikan Job dirancang agar aman ketika diproses lebih dari sekali.
FAQ
Apa itu Failed Jobs di Laravel?
Failed Jobs adalah Job yang tidak berhasil diproses setelah melewati batas percobaan atau mengalami kondisi kegagalan. Laravel menyediakan mekanisme untuk menyimpan dan melihat Job tersebut sehingga dapat dianalisis dan di-retry.
Bagaimana cara melihat Failed Jobs Laravel?
Gunakan:
php artisan queue:failed
Command ini menampilkan ID, connection, queue, dan informasi waktu kegagalan Job.
Bagaimana cara retry Failed Job Laravel?
Gunakan:
php artisan queue:retry JOB_ID
Ganti JOB_ID dengan ID Failed Job yang diperoleh dari php artisan queue:failed.
Bagaimana cara retry semua Failed Jobs?
Gunakan:
php artisan queue:retry all
Namun, pastikan penyebab kegagalan sudah diperbaiki sebelum melakukan retry massal.
Bagaimana cara mengatur jumlah retry Laravel Queue?
Anda dapat menggunakan:
php artisan queue:work redis --tries=3
atau menentukan tries langsung pada Job:
public $tries = 3;
Laravel juga menyediakan retryUntil() sebagai alternatif berbasis waktu.
Apa fungsi backoff pada Laravel Queue?
backoff menentukan berapa lama Laravel menunggu sebelum mencoba kembali Job yang mengalami exception.
Contohnya:
public $backoff = 10;
atau:
public function backoff(): array
{
return [5, 15, 30];
}
Apakah Failed Job harus selalu di-retry?
Tidak.
Retry hanya dilakukan jika penyebab kegagalan sudah diperbaiki dan Job aman untuk dijalankan kembali.
Kenapa Job berhasil tetapi kemudian masuk Failed Jobs?
Salah satu kemungkinan adalah Job sebenarnya sudah melakukan efek samping, tetapi kemudian mengalami exception sebelum proses dianggap selesai. Karena itu, Job yang melakukan transaksi penting sebaiknya dirancang agar idempotent dan aman ketika diproses lebih dari sekali.
