Skip to content
question

Laravel queue jobs do baar run ho rahi hain (jobs running twice), retry_after ka kya chakkar hai?

Faizan Qureshi@faizan_php

October 9, 2026 · 1 min read

Aadab sab ko. School management software mein ek job hai jo ek school ke saare students ki fee receipt PDF banake parents ko email karti hai. Masla ye hai ki kabhi kabhi job do baar chal jaati hai, parents ko do emails jaate hain, aur principal sahab naraz hain.

Setup: Laravel 11, PHP 8.3, QUEUE_CONNECTION=redis, worker: php artisan queue:work --tries=3

class SendFeeReceipts implements ShouldQueue
{
    use Queueable;

    public function __construct(public int $schoolId) {}

    public function handle(): void
    {
        Student::where('school_id', $this->schoolId)
            ->each(function (Student $s) {
                Mail::to($s->parent_email)->send(new FeeReceipt($s));
            });
    }
}

Job mein koi exception nahi aati. Log mein dikhta hai ki same job ID do workers ne utha li, doosre ne lagbhag 90 second baad. Bade school mein (500 students) job 2-3 minute leti hai. Kya ye retry_after wala masla hai? Maazrat agar sawaal basic hai.

Bug ne kaha ek baar chalo, job ne do baar suna,
humne log khole to dekha, worker bhi tha deewana 🙂

Accepted answer

Ayesha Siddiqui#1 in PHP Still Pays3 likes

Haan Faizan, bilkul wahi masla hai, and it is not basic, half the Laravel devs in Pakistan have sent double emails because of this. Redis queue mein jab worker job uthata hai, Laravel use retry_after seconds ke liye reserve karta hai (default 90, config/queue.php mein redis connection). Agar job 90 second mein khatam nahi hui, Laravel samajhta hai worker mar gaya aur job wapas queue mein daal deta hai. Doosra worker utha leta hai. Ab dono chal rahe hain. Exception koi nahi, isliye tumhe kuch dikhta nahi. Fix, isi order mein: 1. config/queue.php mein redis ka 'retry_after' => 600, aur worker ko --timeout=540. Rule: timeout hamesha retry_after se kam. Job class mein bhi public $timeout = 540; rakh do. 2. Asli fix: ek job mein 500 emails mat bhejo. Ek job per student dispatch karo, Bus::batch se, taaki progress aur failures dikhein. Har job 2 second ki hogi, retry_after ka sawaal hi khatam. 3. Idempotency: fee_receipts table mein (student_id, term) unique rakho aur sent_at save karo. Job shuru mein check kare, already sent hai to return. Phir job teen baar bhi chale, parent ko ek hi email jayega. Maine ye May mein Horizon wali post mein likha tha, wahan supervisor config bhi hai. Principal sahab ko mera salaam 😄

View in the thread

Get the best of #php_still_pays weekly

One email each Monday with the most useful posts. No spam; unsubscribe in one click.

Comments

9

Sign in to join the conversation.

Sign in to comment
Oluwatobi Adeyemi@tobi_freelance#6 in PHP Still Pays
Faizan you even wrote poetry for the bug 😂 the bug no go fit vex. Ayesha will come, but yes, it is retry_after
0 net votes

Accepted answer

Ayesha Siddiqui@laravel_ayesha#1 in PHP Still Pays
Haan Faizan, bilkul wahi masla hai, and it is not basic, half the Laravel devs in Pakistan have sent double emails because of this. Redis queue mein jab worker job uthata hai, Laravel use retry_after seconds ke liye reserve karta hai (default 90, config/queue.php mein redis connection). Agar job 90 second mein khatam nahi hui, Laravel samajhta hai worker mar gaya aur job wapas queue mein daal deta hai. Doosra worker utha leta hai. Ab dono chal rahe hain. Exception koi nahi, isliye tumhe kuch dikhta nahi. Fix, isi order mein: 1. config/queue.php mein redis ka 'retry_after' => 600, aur worker ko --timeout=540. Rule: timeout hamesha retry_after se kam. Job class mein bhi public $timeout = 540; rakh do. 2. Asli fix: ek job mein 500 emails mat bhejo. Ek job per student dispatch karo, Bus::batch se, taaki progress aur failures dikhein. Har job 2 second ki hogi, retry_after ka sawaal hi khatam. 3. Idempotency: fee_receipts table mein (student_id, term) unique rakho aur sent_at save karo. Job shuru mein check kare, already sent hai to return. Phir job teen baar bhi chale, parent ko ek hi email jayega. Maine ye May mein Horizon wali post mein likha tha, wahan supervisor config bhi hai. Principal sahab ko mera salaam 😄
3 net votes
Faizan Qureshi@faizan_php#4 in PHP Still Pays
Ayesha baji, behad shukriya. retry_after 600 aur timeout 540 kar diya, aur ab ek job per student. Kal se ek bhi double email nahi gaya. Principal sahab ne chai pilayi 🙂 Ek baar chala job, ek hi email gaya, baji ne jo samjhaya, sab clear ho gaya
2 net votes
Bayu Setiawan@bayu_laravel#2 in PHP Still Pays
Good answer from mbak Ayesha. One small thing Faizan: if you run queue:work without Supervisor, after you change config you must restart the worker (php artisan queue:restart), because the worker keeps old config in memory. I lost one full day to this 🙏
1 net votes
Faizan Qureshi@faizan_php#4 in PHP Still Pays
Bayu bhai, aap ne meri jaan bacha li, pehle din yahi ho raha tha, config badli aur kuch nahi badla 😅 shukriya
1 net votes
Mehmet Aydoğan@malloc_mehmet#8 in PHP Still Pays
In C there is no queue that runs your job twice. Because in C you write your own queue and it runs zero times. PHP.
2 net votes
Faizan Qureshi@faizan_php#4 in PHP Still Pays
Janab, aapka jawab bhi dil ko laga 🙂 aapki queue zero baar chale, hamari do baar, chaliye beech ka raasta, ek baar, mere yaar
0 net votes
John Mark Dela Cruz@jm_delacruz3 rep in PHP Still Pays
bookmarking po, my capstone also sends email receipts. this will happen to me during defense i know it 😭
1 net votes
Ayesha Siddiqui@laravel_ayesha#1 in PHP Still Pays
jm, set retry_after now, before the defense. future you will thank present you
1 net votes