البرمجة متوسط 12 دقيقة

كيفية تشغيل المهام في الخلفية باستخدام طوابير Laravel

كل شيء لا يجب أن يحدث قبل أن تتمكن من الرد على المستخدم ينتمي إلى طابور. إرسال بريد ترحيب، تغيير حجم صورة مرفوعة، استدعاء واجهة API خارجية، توليد ملف PDF — لا شيء من هذا يجب أن يُعيق استجابة HTTP. الطوابير تنقل هذا العمل إلى عامل في الخلفية، مما يُبقي أوقات الاستجابة منخفضة وعمليات إعادة المحاولة تلقائية.

نظام الطوابير في Laravel هو أحد أفضل ميزاته. واجهة موحدة تخفي ما إذا كان برنامج التشغيل جدول قاعدة بيانات أو Redis أو SQS أو غيره. هذا الدليل يستخدم برنامج تشغيل قاعدة البيانات — بدون بنية تحتية إضافية، يعمل في كل مكان.

الخطوات

  1. 1

    ضبط برنامج تشغيل الطابور

    اضبط QUEUE_CONNECTION=database في ملف .env. ثم أنشئ migration جدول المهام وشغّله. هذا ينشئ جدولي jobs وfailed_jobs حيث ستوجد إدخالات الطابور.

    bash
    # .env
    QUEUE_CONNECTION=database
    
    # Generate and run the migrations
    php artisan queue:table
    php artisan queue:failed-table
    php artisan migrate
  2. 2

    إنشاء كلاس Job

    أنشئ مهمة بـ make:job. يحصل الكلاس على طريقة handle() حيث يحدث العمل. أدخل أي اعتماديات مباشرة — حاوية الخدمة تحلها عندما يلتقط العامل المهمة.

    bash
    php artisan make:job SendWelcomeEmail
  3. 3

    تنفيذ المهمة

    نفّذ ShouldQueue لإخبار Laravel أن هذه المهمة مُضافة للطابور (لا تزامنية). خزّن فقط ما تحتاجه في المُنشئ — عادةً النموذج أو كائن قيمة صغير. تجنب تخزين مصفوفات كبيرة أو كائنات طلب كاملة؛ فهي تُضخّم حجم المهمة المتسلسلة.

    php
    <?php
    
    namespace App\Jobs;
    
    use App\Mail\WelcomeMail;
    use App\Models\User;
    use Illuminate\Bus\Queueable;
    use Illuminate\Contracts\Queue\ShouldQueue;
    use Illuminate\Foundation\Bus\Dispatchable;
    use Illuminate\Queue\InteractsWithQueue;
    use Illuminate\Queue\SerializesModels;
    use Illuminate\Support\Facades\Mail;
    
    class SendWelcomeEmail implements ShouldQueue
    {
        use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
    
        public int $tries = 3;          // Retry up to 3 times
        public int $backoff = 60;       // Wait 60s between retries
    
        public function __construct(
            public readonly User $user
        ) {}
    
        public function handle(): void
        {
            Mail::to($this->user)->send(new WelcomeMail($this->user));
        }
    
        public function failed(\Throwable $exception): void
        {
            // Notify the team, log, or clean up
            logger()->error('SendWelcomeEmail failed', [
                'user_id' => $this->user->id,
                'error'   => $exception->getMessage(),
            ]);
        }
    }
  4. 4

    إرسال المهمة إلى الطابور

    أرسل من أي مكان — controller أو service أو مستمع لحدث. تُسلسَل المهمة، تُكتب إلى جدول jobs، ويلتقطها العامل بشكل غير متزامن. استخدم dispatch() للإضافة الفورية أو dispatch()->delay() لجدولتها لاحقاً.

    php
    use App\Jobs\SendWelcomeEmail;
    
    // In a controller after registration
    SendWelcomeEmail::dispatch($user);
    
    // Delay by 5 minutes
    SendWelcomeEmail::dispatch($user)->delay(now()->addMinutes(5));
    
    // Send to a specific queue (useful for prioritisation)
    SendWelcomeEmail::dispatch($user)->onQueue('emails');
    
    // Dispatch only if condition is met
    SendWelcomeEmail::dispatchIf($user->wants_email, $user);
  5. 5

    تشغيل العامل

    العامل يسحب المهام من الطابور وينفذها. استخدم queue:work في التطوير. يعالج المهام باستمرار حتى توقفه. للإنتاج استخدم مدير عمليات — Supervisor يضمن إعادة تشغيل العامل تلقائياً عند تعطله.

    bash
    # Development
    php artisan queue:work
    
    # Process a specific queue with timeout and memory limit
    php artisan queue:work --queue=emails,default --timeout=60 --memory=128
    
    # Process a single job then exit (useful in cron-based setups)
    php artisan queue:work --once
  6. 6

    ضبط Supervisor للإنتاج

    Supervisor يُبقي عملية العامل تعمل على الخادم. أنشئ ملف ضبط في /etc/supervisor/conf.d/. إعداد numprocs يتحكم في عدد عمليات العمال المتوازية — اضبطه بناءً على حجم المهام وموارد الخادم.

    ini
    [program:laravel-worker]
    process_name=%(program_name)s_%(process_num)02d
    command=php /var/www/esb1995.com/artisan queue:work database --sleep=3 --tries=3 --timeout=90
    autostart=true
    autorestart=true
    stopasgroup=true
    killasgroup=true
    user=apache
    numprocs=2
    redirect_stderr=true
    stdout_logfile=/var/log/worker.log
    stopwaitsecs=3600
  7. 7

    مراقبة المهام الفاشلة وإعادة محاولتها

    عندما تتجاوز مهمة حد $tries، تصل إلى جدول failed_jobs. استخدم أوامر Artisan للفحص وإعادة المحاولة. في الإنتاج، فكر في إعداد تنبيهات عند ازدياد عدد المهام الفاشلة — هذا يعني أن شيئاً ما مكسور في مكان ما.

    bash
    # List all failed jobs
    php artisan queue:failed
    
    # Retry a specific failed job by its UUID
    php artisan queue:retry 5
    
    # Retry all failed jobs
    php artisan queue:retry all
    
    # Delete a specific failed job
    php artisan queue:forget 5
    
    # Delete all failed jobs
    php artisan queue:flush
  8. 8

    إعادة تشغيل العمال بعد النشر

    العمال يحملون كود التطبيق عند البدء. إذا نشرت كوداً جديداً دون إعادة تشغيل العمال، ستستمر العمليات الجارية في استخدام الكود القديم. النمط الآمن هو إشارة إعادة تشغيل بعد كل نشر — ينهي العامل مهمته الحالية ثم يخرج بشكل نظيف ليعيد Supervisor تشغيله بالكود الجديد.

    bash
    # Add this to your deploy script after git pull + optimize
    php artisan queue:restart
    
    # Supervisor will automatically start fresh workers with new code
    # (queue:restart signals via the cache — ensure your cache driver is shared)

نصائح ومحاذير

  • استخدم طوابير مسماة لترتيب الأولويات: <code>--queue=critical,high,default</code>. العامل يُفرغ <code>critical</code> كلياً قبل أن يلمس <code>high</code>. ضع معالجة المدفوعات في <code>critical</code> والبريد الإلكتروني في <code>default</code>.
  • اضبط <code>$timeout</code> على كلاس المهمة لإيقاف المهام المعلقة. بدونه، مهمة عالقة تحجز مكان عامل إلى الأبد.
  • تجنب تخزين مجموعات Eloquent كاملة في منشئ المهمة. اسحب ما تحتاجه داخل <code>handle()</code> — البيانات قد تكون تغيرت بين الإرسال والتنفيذ.
  • <code>queue:work</code> يحمّل تطبيقك مرة واحدة ويبقيه في الذاكرة. تغييرات الكود لا تُلتقط حتى يُعاد تشغيل العامل. شغّل دائماً <code>queue:restart</code> بعد النشر.
  • للتطوير المحلي، اضبط <code>QUEUE_CONNECTION=sync</code> في <code>.env</code> — المهام تعمل فوراً دون الحاجة لعامل، مما يجعل التصحيح أسهل بكثير.

خاتمة

الطوابير ليست تحسيناً — بل هي البنية الصحيحة لأي عمل لا يجب أن يعيق الاستجابة. اجعل برنامج تشغيل قاعدة البيانات يعمل محلياً، ثم انتقل إلى Redis في الإنتاج لأداء أفضل.

#Laravel #Queues #Background
العودة إلى جميع الأدلة

هل تحتاج مساعدة في مشروعك؟

احجز استشارة مجانية لمدة 30 دقيقة لمناقشة تحدياتك التقنية واستكشاف الحلول معًا.