Laravel Queue Delay dan Retry: Mengatur Job yang Perlu Dijadwalkan Ulang
Apa Itu Queue Delay dan Retry di Laravel?
Laravel Queue memungkinkan aplikasi menjalankan pekerjaan di background menggunakan Job.
Dalam kondisi tertentu, Job tidak harus langsung dijalankan.
Misalnya:
- Mengirim email 5 menit setelah user mendaftar
- Mengirim reminder beberapa jam kemudian
- Menunggu beberapa saat sebelum memanggil API lagi
- Mencoba kembali Job yang gagal
- Memberikan jeda ketika API eksternal mengalami masalah sementara
Laravel menyediakan dua konsep penting untuk kebutuhan tersebut:
Delay digunakan untuk menentukan kapan Job mulai tersedia untuk diproses.
Retry digunakan ketika Job gagal dan perlu dicoba kembali.
Secara sederhana:
Delay
Dispatch Job
↓
Menunggu
↓
Queue Worker
↓
Proses Job
Sedangkan Retry:
Job
↓
Gagal
↓
Retry
↓
Gagal
↓
Retry
↓
Berhasil
Kedua fitur ini sangat berguna ketika aplikasi mulai menggunakan Queue untuk email, API, import data, notifikasi, dan proses background lainnya.
Mengapa Job Perlu Menggunakan Delay?
Tidak semua pekerjaan harus langsung dilakukan.
Misalnya setelah user melakukan registrasi:
User Register
↓
Akun berhasil dibuat
↓
Kirim Welcome Email
Jika email langsung dikirim, mungkin tidak ada masalah.
Tetapi untuk beberapa kebutuhan, kita mungkin ingin memberikan jeda:
User Register
↓
Akun berhasil dibuat
↓
Delay 5 menit
↓
Kirim Welcome Email
Contoh lainnya adalah reminder.
Order Dibuat
↓
Delay 24 Jam
↓
Cek Status Order
↓
Kirim Reminder jika diperlukan
Dengan Queue Delay, aplikasi tidak perlu menggunakan cron atau scheduler untuk setiap pekerjaan yang hanya membutuhkan penundaan sederhana.
Cara Memberikan Delay pada Laravel Job
Cara paling sederhana adalah menggunakan delay() ketika melakukan dispatch.
Contoh:
SendWelcomeEmail::dispatch($user)
->delay(now()->addMinutes(5));
Job tersebut tidak langsung tersedia untuk diproses.
Laravel akan menunggu sampai waktu yang ditentukan sebelum Job dapat diambil oleh Worker.
Contoh delay 1 jam:
SendWelcomeEmail::dispatch($user)
->delay(now()->addHour());
Atau:
SendWelcomeEmail::dispatch($user)
->delay(now()->addHours(1));
Delay dengan Waktu Tertentu
Delay juga dapat menggunakan waktu tertentu.
Contohnya:
SendReminder::dispatch($order)
->delay(now()->addDay());
Atau menggunakan waktu yang sudah dihitung:
$sendAt = now()->addHours(3);
SendReminder::dispatch($order)
->delay($sendAt);
Ini berguna ketika waktu eksekusi ditentukan berdasarkan kondisi bisnis.
Delay Berdasarkan Data
Misalnya setiap order memiliki waktu reminder:
$sendAt = $order->reminder_at;
SendOrderReminder::dispatch($order)
->delay($sendAt);
Dengan demikian, setiap Job dapat memiliki jadwal yang berbeda.
Contohnya:
Order #101 → 10:00
Order #102 → 11:00
Order #103 → 13:00
Queue Worker akan mengambil Job ketika waktunya sudah tersedia.
Delay pada Constructor Job
Delay juga dapat ditentukan ketika membuat Job.
Contoh:
class SendReminder implements ShouldQueue
{
use Queueable;
public function __construct(
public Order $order
) {}
public function handle(): void
{
// Kirim reminder
}
}
Kemudian:
SendReminder::dispatch($order)
->delay(now()->addHours(2));
Pendekatan ini biasanya lebih fleksibel karena waktu delay dapat ditentukan oleh bagian aplikasi yang melakukan dispatch.
Delay vs Laravel Scheduler
Delay dan Scheduler memiliki tujuan yang berbeda.
Queue Delay cocok ketika kita ingin menjadwalkan satu Job tertentu untuk diproses nanti.
Laravel Scheduler cocok untuk menjalankan task berdasarkan jadwal berulang.
Contohnya:
Queue Delay
Order dibuat
↓
Delay 2 jam
↓
SendReminder Job
Sedangkan Scheduler:
Setiap hari pukul 08:00
↓
Jalankan task
↓
Generate Report
Jadi jangan menganggap Queue Delay sebagai pengganti Scheduler.
Apa Itu Retry pada Laravel Queue?
Retry berarti menjalankan kembali Job yang gagal.
Contohnya:
Job
↓
API Request
↓
Timeout
↓
Retry
↓
API Request
↓
Berhasil
Retry sangat berguna untuk error yang sifatnya sementara.
Contohnya:
- API eksternal timeout
- Network connection gagal
- Service sementara tidak tersedia
- Database mengalami gangguan sementara
- Rate limit
- Resource eksternal belum siap
Namun, tidak semua error harus di-retry.
Jika error disebabkan bug permanen, retry berulang kali hanya membuang resource.
Mengatur Jumlah Retry dengan $tries
Kita dapat menentukan jumlah percobaan Job.
Contoh:
class ProcessOrder implements ShouldQueue
{
public $tries = 3;
public function handle(): void
{
// Proses Job
}
}
Dengan konfigurasi tersebut, Laravel dapat mencoba Job beberapa kali sebelum akhirnya dianggap gagal.
Secara konsep:
Attempt 1
↓
Gagal
↓
Attempt 2
↓
Gagal
↓
Attempt 3
↓
Gagal
↓
Failed Job
Jumlah percobaan harus disesuaikan dengan jenis pekerjaan.
Retry Tidak Selalu Berarti Error Harus Hilang
Misalnya Job melakukan request ke API:
$response = Http::timeout(10)
->post($url, $data);
Jika API timeout, retry mungkin membantu.
Tetapi jika request gagal karena:
HTTP 400
Invalid data
retry kemungkinan tidak akan memperbaiki masalah.
Karena data request tetap salah.
Karena itu, strategi retry harus membedakan antara:
Transient Error
→ Layak di-retry
dan:
Permanent Error
→ Perlu diperbaiki atau ditandai gagal
Menggunakan backoff untuk Retry
Jangan selalu melakukan retry secara langsung.
Bayangkan API eksternal sedang mengalami gangguan.
Jika 1.000 Job gagal lalu semuanya langsung retry:
1.000 Job gagal
↓
1.000 Retry sekaligus
↓
API semakin terbebani
Kondisi seperti ini dapat memperparah masalah.
Kita dapat menggunakan backoff untuk memberikan jeda sebelum retry.
Contoh:
class SyncProduct implements ShouldQueue
{
public $tries = 3;
public $backoff = 10;
public function handle(): void
{
// Sinkronisasi produk
}
}
Artinya Job memiliki jeda sebelum percobaan ulang sesuai konfigurasi backoff.
Backoff Bertahap
Kita juga dapat menggunakan array untuk menentukan jeda retry.
Contoh:
public function backoff(): array
{
return [10, 30, 60];
}
Konsepnya:
Attempt 1
↓
Gagal
↓
Tunggu 10 detik
↓
Attempt 2
↓
Gagal
↓
Tunggu 30 detik
↓
Attempt 3
↓
Gagal
↓
Tunggu 60 detik
Format dan perilaku detail dapat bergantung pada versi Laravel yang digunakan, jadi pastikan implementasi mengikuti dokumentasi versi Laravel project.
Exponential Backoff
Untuk API eksternal atau service yang mengalami gangguan, exponential backoff sering menjadi strategi yang baik.
Contohnya:
10 detik
30 detik
60 detik
120 detik
Semakin banyak percobaan, semakin panjang jedanya.
Tujuannya adalah memberikan waktu kepada service yang bermasalah untuk pulih.
Contoh implementasi dinamis:
public function backoff(): array
{
return [10, 30, 60, 120];
}
Jika jumlah retry hanya tiga, tidak semua nilai tersebut tentu akan digunakan.
Retry dengan Delay yang Berbeda
Misalnya kita memiliki Job:
class SyncProduct implements ShouldQueue
{
public $tries = 4;
public function backoff(): array
{
return [10, 30, 60];
}
public function handle(): void
{
// Sync product
}
}
Alurnya:
Attempt 1
↓
Gagal
↓
10 detik
↓
Attempt 2
↓
Gagal
↓
30 detik
↓
Attempt 3
↓
Gagal
↓
60 detik
↓
Attempt 4
Setelah percobaan terakhir gagal, Job dapat masuk ke failed jobs sesuai konfigurasi aplikasi.
Retry dan Timeout Harus Dipikirkan Bersama
timeout menentukan berapa lama sebuah Job boleh berjalan.
Contoh:
public $timeout = 120;
Artinya Job memiliki batas waktu sekitar 120 detik.
Sedangkan:
public $tries = 3;
mengatur jumlah percobaan.
Keduanya berbeda:
Timeout
→ Berapa lama satu attempt boleh berjalan?
Tries
→ Berapa kali Job boleh dicoba?
Misalnya:
tries = 3
timeout = 120
Secara kasar, satu Job dapat memiliki beberapa attempt dengan masing-masing batas waktu tersebut, ditambah waktu backoff dan overhead lainnya.
Karena itu, jangan menentukan timeout dan retry tanpa mempertimbangkan total waktu yang mungkin dibutuhkan.
Retry untuk API Eksternal
API eksternal merupakan salah satu contoh paling cocok untuk retry.
Misalnya:
$response = Http::timeout(10)
->get($url);
Jika API mengalami timeout sementara, Job dapat dicoba kembali.
Contoh:
class SyncProduct implements ShouldQueue
{
public $tries = 3;
public $timeout = 30;
public function backoff(): array
{
return [10, 30];
}
public function handle(): void
{
Http::timeout(10)
->get('https://example.com/api/products');
}
}
Alurnya:
Request API
↓
Timeout
↓
Tunggu 10 detik
↓
Retry
↓
Gagal
↓
Tunggu 30 detik
↓
Retry
Untuk implementasi production, sebaiknya tambahkan penanganan response HTTP dan bedakan error yang memang layak di-retry.
Retry dan HTTP Status Code
Tidak semua HTTP status code sebaiknya di-retry.
Contoh:
429 Too Many Requests
→ Sering layak di-retry
500 Internal Server Error
→ Dapat layak di-retry
502 Bad Gateway
→ Dapat layak di-retry
503 Service Unavailable
→ Dapat layak di-retry
400 Bad Request
→ Biasanya tidak perlu retry
401 Unauthorized
→ Perbaiki authentication
404 Not Found
→ Belum tentu perlu retry
Strategi sebenarnya bergantung pada API yang digunakan.
Jika API memberikan informasi Retry-After, aplikasi juga sebaiknya mempertimbangkan nilai tersebut.
Retry-After dari API
Beberapa API dapat mengembalikan header:
Retry-After
Misalnya:
HTTP 429
Retry-After: 60
Artinya server meminta client menunggu sekitar 60 detik sebelum mencoba lagi.
Untuk integrasi API production, lebih baik menghormati mekanisme seperti ini daripada melakukan retry secara agresif.
Menangani Rate Limit
Misalnya aplikasi mengirim terlalu banyak request:
Laravel Queue
↓
API
↓
429 Too Many Requests
Jika semua Job langsung retry:
429
↓
Retry
↓
429
↓
Retry
↓
429
Ini tidak efektif.
Gunakan:
- Backoff
- Rate limiting
- Delay
- Queue throttling
- Concurrency control
Dengan demikian request dapat diproses secara lebih terkontrol.
Job Retry dan Idempotency
Retry membawa satu risiko penting: Job dapat dijalankan lebih dari satu kali.
Contoh:
Process Payment
↓
Payment berhasil
↓
Response timeout
↓
Job menganggap gagal
↓
Retry
Jika tidak ada perlindungan, pembayaran dapat dilakukan dua kali.
Karena itu, Job yang memiliki efek samping harus dirancang idempotent.
Contoh gunakan transaction reference:
transaction_id = INV-2026-001
Sebelum melakukan proses:
Apakah INV-2026-001 sudah diproses?
│
Ya ───→ Jangan proses lagi
│
Tidak
↓
Proses
Ini sangat penting untuk:
- Payment
- Order
- Invoice
- Sinkronisasi data
- Pengiriman request ke API
- Perubahan status transaksi
Jangan Retry Error Permanen
Misalnya Job menjalankan:
$order->update([
'status' => 'completed',
]);
tetapi ternyata $order tidak ditemukan.
Retry tiga kali tidak akan membuat order tiba-tiba muncul.
Error seperti ini lebih baik diperbaiki atau ditangani sebagai kondisi bisnis daripada terus di-retry.
Contoh lainnya:
Invalid API credential
Tidak ada gunanya melakukan:
Retry 1
Retry 2
Retry 3
Retry 4
...
sampai credential diperbaiki.
Menangani Failed Job
Jika seluruh percobaan gagal, Job dapat masuk ke daftar failed jobs.
Kita dapat melihatnya dengan:
php artisan queue:failed
Contoh:
2026-08-23 01:00:00
Job ID: 123
Connection: redis
Queue: default
Job: App\Jobs\SyncProduct
Setelah penyebab error diperbaiki, Job dapat dicoba kembali:
php artisan queue:retry 123
ID disesuaikan dengan Job yang ingin di-retry.
Retry Semua Failed Jobs
Jika memang diperlukan, Laravel juga menyediakan mekanisme untuk mencoba kembali beberapa atau seluruh failed jobs sesuai command yang tersedia pada versi Laravel.
Namun, jangan melakukan retry massal tanpa memahami penyebab kegagalan.
Misalnya 10.000 Job gagal karena API sedang down.
Jika semuanya langsung di-retry:
10.000 Failed Jobs
↓
10.000 Retry
↓
API Overload
Lebih baik perbaiki penyebabnya terlebih dahulu dan lakukan retry secara terkontrol.
Menghapus Failed Job
Jika Job tidak perlu diproses kembali, kita dapat menghapusnya menggunakan command yang tersedia:
php artisan queue:forget <id>
Gunakan ID failed Job yang sesuai.
Untuk menghapus seluruh failed jobs, Laravel juga memiliki command terkait. Sebelum menjalankannya di production, pastikan Job memang tidak lagi dibutuhkan.
Method failed()
Kita dapat menjalankan logic tertentu ketika Job akhirnya gagal.
Contoh:
public function failed(?Throwable $exception): void
{
Log::error('Sync product gagal', [
'product_id' => $this->productId,
'error' => $exception?->getMessage(),
]);
}
Ini berguna untuk:
- Logging
- Mengubah status menjadi
failed - Mengirim notifikasi admin
- Mencatat alasan kegagalan
- Membuat audit trail
Contoh Job dengan Delay, Retry, Backoff, dan Timeout
Berikut contoh Job yang menggabungkan beberapa fitur:
<?php
namespace App\Jobs;
use App\Models\Product;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Throwable;
class SyncProduct implements ShouldQueue
{
use Queueable;
public $tries = 3;
public $timeout = 60;
public function __construct(
public Product $product
) {}
public function backoff(): array
{
return [10, 30];
}
public function handle(): void
{
$response = Http::timeout(30)
->post('https://example.com/api/products', [
'id' => $this->product->id,
'name' => $this->product->name,
]);
$response->throw();
}
public function failed(?Throwable $exception): void
{
Log::error('Product sync failed', [
'product_id' => $this->product->id,
'error' => $exception?->getMessage(),
]);
}
}
Dispatch langsung:
SyncProduct::dispatch($product);
Atau dengan delay:
SyncProduct::dispatch($product)
->delay(now()->addMinutes(5));
Alurnya:
Dispatch
↓
Delay 5 menit
↓
Attempt 1
↓
Gagal
↓
10 detik
↓
Attempt 2
↓
Gagal
↓
30 detik
↓
Attempt 3
↓
Gagal
↓
failed()
Delay pada Job Tidak Berarti Worker Berhenti
Ini konsep yang penting.
Jika Job memiliki delay:
SendReminder::dispatch($order)
->delay(now()->addHour());
Worker tidak harus berhenti menunggu satu Job tersebut.
Worker dapat memproses Job lain yang sudah tersedia.
Contohnya:
Queue
├── Reminder A → Delay 1 jam
├── Email B → Ready
└── Order C → Ready
Worker dapat memproses:
Email B
↓
Order C
↓
...
sementara Reminder A menunggu sampai waktunya tersedia.
Delay vs Retry Backoff
Keduanya sama-sama melibatkan waktu tunggu, tetapi konteksnya berbeda.
Delay:
Job::dispatch()
->delay(now()->addMinutes(10));
Digunakan untuk menunda Job sebelum pertama kali diproses.
Backoff:
public function backoff(): array
{
return [10, 30];
}
Digunakan untuk menentukan jeda sebelum percobaan ulang setelah Job gagal.
Jadi:
Delay
→ Kapan Job pertama kali boleh diproses?
Backoff
→ Berapa lama menunggu setelah Job gagal?
Delay, Retry, dan Scheduler
Ketiganya sering dianggap sama, padahal berbeda.
| Fitur | Fungsi |
|---|---|
| Queue Delay | Menunda Job tertentu |
| Queue Retry | Mengulang Job yang gagal |
| Backoff | Mengatur jeda sebelum retry |
| Scheduler | Menjalankan task berdasarkan jadwal |
| Queue Worker | Memproses Job dari Queue |
Contohnya:
Scheduler
↓
Setiap hari pukul 08:00
↓
Dispatch Job
↓
Queue
↓
Worker
↓
Process Job
Sedangkan:
Controller
↓
Dispatch Job
↓
Delay 1 jam
↓
Queue Worker
↓
Process Job
Mengatur Retry pada Command Queue Worker
Selain konfigurasi pada Job, Worker juga memiliki opsi terkait retry dan timeout.
Contoh:
php artisan queue:work redis --tries=3 --timeout=120
Dengan command tersebut, Worker dijalankan menggunakan Redis dan diberikan konfigurasi retry serta timeout.
Konfigurasi pada Job dan Worker dapat berinteraksi. Karena itu, pastikan memahami konfigurasi project agar tidak terjadi konflik atau ekspektasi yang berbeda.
Jangan Menyamakan $tries dengan --tries
Kamu mungkin menemukan dua bentuk konfigurasi:
Pada Job:
public $tries = 3;
Pada Worker:
php artisan queue:work --tries=3
Keduanya berkaitan dengan jumlah percobaan, tetapi memiliki konteks konfigurasi berbeda.
Untuk konfigurasi yang spesifik terhadap Job, mendefinisikannya pada Job dapat membuat perilakunya lebih jelas.
Contohnya:
class SyncProduct implements ShouldQueue
{
public $tries = 5;
}
Job tersebut memiliki kebutuhan retry sendiri.
Mengatur Retry Berdasarkan Waktu
Laravel juga mendukung konsep membatasi retry berdasarkan waktu melalui konfigurasi Job tertentu.
Misalnya daripada menentukan jumlah percobaan:
public $tries = 10;
kita dapat menggunakan batas waktu retry sesuai kebutuhan.
Konsepnya:
Selama belum melewati batas waktu
↓
Boleh retry
Setelah batas waktu
↓
Failed
Fitur yang tersedia dan detail implementasinya dapat berbeda berdasarkan versi Laravel.
Untuk project production, pastikan mengacu pada API Queue versi Laravel yang sedang digunakan.
Retry yang Aman untuk Database
Misalnya Job memperbarui database:
public function handle(): void
{
$order = Order::findOrFail($this->orderId);
$order->update([
'status' => 'processed',
]);
}
Jika Job gagal setelah update tetapi sebelum menyelesaikan proses lainnya, retry dapat menjalankan update kembali.
Untuk operasi kompleks, gunakan transaction atau desain idempotency agar retry tidak menyebabkan kondisi data yang tidak diinginkan.
Contohnya:
DB::transaction(function () {
// Proses database
});
Namun transaction tidak otomatis membuat seluruh Job idempotent. Efek samping eksternal seperti email atau API tetap perlu dipikirkan secara terpisah.
Queue Retry dan Email
Email merupakan kasus yang menarik.
Misalnya:
Send Invoice Email
↓
SMTP Timeout
↓
Retry
Retry dapat membantu jika SMTP hanya mengalami gangguan sementara.
Tetapi jika email sudah diterima oleh mail server namun response timeout terjadi, retry dapat berpotensi mengirim email dua kali.
Untuk email penting, pertimbangkan:
- Unique message/reference ID
- Status pengiriman
- Idempotency
- Mail provider yang mendukung tracking
- Mekanisme deduplikasi
Queue Retry dan API Payment
Payment membutuhkan perhatian lebih besar.
Jangan membuat Job seperti:
public function handle()
{
PaymentGateway::charge($this->amount);
}
kemudian membiarkan Laravel retry secara otomatis tanpa idempotency.
Lebih aman menggunakan payment reference unik:
ORDER-2026-001
Kemudian API payment gateway dapat menggunakan reference tersebut untuk memastikan request yang sama tidak diproses dua kali jika fitur tersebut didukung.
Konsep pentingnya:
Retry ≠ Aman secara otomatis
Developer harus merancang Job agar retry tidak menyebabkan efek samping ganda.
Monitoring Retry
Jika sebuah Job terus-menerus retry, itu merupakan sinyal bahwa ada masalah.
Misalnya:
SyncProduct
↓
Retry 1
↓
Retry 2
↓
Retry 3
↓
Failed
Jika terjadi pada ribuan Job, cari penyebab utamanya.
Kemungkinan:
- API down
- Redis bermasalah
- Database lambat
- Credential expired
- Bug aplikasi
- Rate limit
- Network issue
Jangan hanya menaikkan:
public $tries = 20;
tanpa mencari penyebab kegagalan.
Laravel Horizon untuk Monitoring Queue Redis
Jika aplikasi menggunakan Redis sebagai Queue backend, Laravel Horizon dapat membantu memonitor Queue.
Horizon menyediakan informasi mengenai:
- Job yang sedang diproses
- Job yang selesai
- Failed jobs
- Runtime
- Queue throughput
- Worker
Ini sangat berguna ketika aplikasi memiliki banyak Job dan retry.
Dengan monitoring, kita dapat melihat apakah suatu Job sering gagal dan membutuhkan retry berulang.
Contoh Strategi Retry untuk API
Untuk API yang dapat mengalami gangguan sementara, strategi sederhana dapat berupa:
Attempt 1
↓
Gagal
↓
10 detik
Attempt 2
↓
Gagal
↓
30 detik
Attempt 3
↓
Gagal
↓
Failed
Implementasi:
public $tries = 3;
public function backoff(): array
{
return [10, 30];
}
Ini jauh lebih baik daripada:
Attempt 1
↓
Gagal
↓
Retry langsung
Attempt 2
↓
Gagal
↓
Retry langsung
terutama ketika error berasal dari service eksternal yang sedang bermasalah.
Best Practice Laravel Queue Delay dan Retry
Beberapa praktik yang sebaiknya diterapkan:
Gunakan Delay untuk Pekerjaan yang Memang Tidak Perlu Langsung Diproses
Contoh:
SendReminder::dispatch($order)
->delay(now()->addHours(2));
Gunakan Retry untuk Error Transient
Contohnya:
- Timeout
- Connection error
- HTTP 502
- HTTP 503
- Rate limit
Jangan Retry Error Permanen
Contohnya:
- Data invalid
- Credential salah
- Resource memang tidak ditemukan
Gunakan Backoff
Contoh:
public function backoff(): array
{
return [10, 30, 60];
}
Tentukan Timeout yang Masuk Akal
public $timeout = 120;
Jangan menggunakan timeout terlalu tinggi hanya untuk menyembunyikan Job yang lambat.
Rancang Job agar Idempotent
Terutama untuk:
- Payment
- Order
- Invoice
- API
- Sinkronisasi
Monitor Failed Jobs
Gunakan:
php artisan queue:failed
dan monitoring seperti Horizon jika menggunakan Redis.
Jangan Retry Secara Membabi Buta
Jika ribuan Job gagal karena service eksternal down, retry massal dapat memperparah masalah.
Contoh Alur Production
Untuk aplikasi Laravel dengan Redis:
Laravel
│
↓
Dispatch Job
│
↓
Redis
│
↓
Queue Worker
│
┌─────┴─────┐
│ │
Success Failed
│ │
↓ ↓
Selesai Backoff
│
↓
Retry
│
┌─────────┴─────────┐
↓ ↓
Success Failed
│ │
↓ ↓
Selesai Failed Jobs
Dengan arsitektur ini, Laravel dapat menangani pekerjaan background dengan lebih terkontrol.
Kesimpulan
Laravel Queue Delay dan Retry membantu mengatur kapan sebuah Job diproses dan apa yang harus dilakukan ketika Job mengalami kegagalan.
Untuk menunda Job:
SendReminder::dispatch($order)
->delay(now()->addHours(2));
Untuk membatasi percobaan:
public $tries = 3;
Untuk memberikan jeda sebelum retry:
public function backoff(): array
{
return [10, 30, 60];
}
Sedangkan timeout dapat diatur sesuai kebutuhan:
public $timeout = 120;
Konsep yang paling penting adalah membedakan:
Delay
→ Menunda Job sebelum diproses
Retry
→ Mencoba kembali Job yang gagal
Backoff
→ Menentukan jeda sebelum retry
Timeout
→ Membatasi durasi satu attempt
Jangan lupa bahwa retry bukan berarti Job otomatis aman dijalankan berkali-kali. Untuk pekerjaan seperti payment, order, invoice, dan integrasi API, Job sebaiknya dirancang idempotent agar retry tidak menyebabkan efek samping ganda.
Dengan kombinasi Queue + Delay + Retry + Backoff + Monitoring, background processing Laravel menjadi jauh lebih tahan terhadap error sementara dan gangguan service eksternal.
