فهم Laravel Queues و Jobs في التطبيقات الحقيقية
في التطبيقات الصغيرة يمكن تنفيذ كل شيء داخل الطلب نفسه. المستخدم يرسل الطلب، الخادم يعالج العملية، ثم يرجع الاستجابة.
لكن مع زيادة تعقيد التطبيق تبدأ بعض العمليات تصبح مكلفة زمنيًا.
- إرسال بريد إلكتروني
- معالجة ملفات
- رفع صور
- إرسال إشعارات
- تكامل مع APIs خارجية
تنفيذ هذه العمليات داخل الطلب نفسه يبطئ الاستجابة بشكل واضح.
هنا يأتي دور نظام Queues في Laravel.
المشكلة التي تحلها Queues
الهدف الأساسي من Queues هو فصل العمليات الثقيلة عن دورة الطلب الأساسية.
بدل تنفيذ العملية مباشرة أثناء الطلب، يتم وضعها داخل Queue ليتم تنفيذها لاحقًا بواسطة Worker.
بهذا الشكل:
- يستجيب التطبيق بسرعة
- يتم تنفيذ العمليات في الخلفية
- يمكن التحكم في عدد العمال الذين يعالجون المهام
كيف يعمل النظام داخليًا
Laravel Queue يعتمد على فكرة بسيطة:
الوظائف الثقيلة تتحول إلى Jobs.
هذه الـ Jobs يتم دفعها إلى Queue backend مثل:
- database
- redis
- beanstalkd
- sqs
بعد ذلك يقوم Worker بقراءة هذه المهام وتنفيذها.
الـ Worker يعمل عادة كعملية مستقلة عن التطبيق.
إنشاء Job في Laravel
Laravel يوفر طريقة مباشرة لإنشاء Job:
php artisan make:job SendWelcomeEmail
سيتم إنشاء الكلاس داخل:
app/Jobs/SendWelcomeEmail.php
الجزء الأساسي في الـ Job هو دالة handle.
class SendWelcomeEmail implements ShouldQueue
{
use Dispatchable, Queueable;
public function __construct(public User $user)
{
}
public function handle()
{
Mail::to($this->user->email)
->send(new WelcomeMail($this->user));
}
}
وجود ShouldQueue يعني أن المهمة ستدخل في Queue بدل التنفيذ الفوري.
إرسال Job إلى Queue
لدفع المهمة إلى Queue يتم استخدام dispatch:
SendWelcomeEmail::dispatch($user);
عند تنفيذ هذا السطر:
- يتم تحويل الكائن إلى payload
- تخزينه في backend queue
- ينتظر worker لتنفيذه
تشغيل Worker
الـ Worker هو العملية التي تقرأ المهام من Queue.
php artisan queue:work
يقوم Laravel بالآتي:
- قراءة المهمة من Queue
- إعادة بناء الكائن
- تشغيل دالة handle
عادة يتم تشغيل workers عبر Supervisor في بيئة الإنتاج.
اختيار Queue Driver
Laravel يدعم عدة drivers.
Database driver سهل للاستخدام لكنه ليس الأفضل للأداء.
Redis غالبًا هو الخيار الأكثر استخدامًا لأنه:
- سريع
- مناسب للأحمال العالية
- يدعم عمليات queue بكفاءة
لذلك في الأنظمة الإنتاجية غالبًا يتم استخدام Redis.
إعادة المحاولة ومعالجة الأخطاء
المهام قد تفشل لأسباب مختلفة:
- انقطاع الشبكة
- خطأ في API خارجي
- استثناء داخل الكود
Laravel يسمح بإعادة المحاولة تلقائيًا.
public $tries = 3;
بهذا الشكل تتم إعادة تنفيذ المهمة حتى ثلاث مرات قبل اعتبارها فاشلة.
المهام الفاشلة يتم تسجيلها في جدول:
failed_jobs
تأخير تنفيذ المهام
أحيانًا لا تريد تنفيذ المهمة فورًا.
يمكن تأخيرها بسهولة:
SendWelcomeEmail::dispatch($user)
->delay(now()->addMinutes(10));
بهذا الشكل سيتم تنفيذ المهمة بعد 10 دقائق.
تقسيم الأحمال باستخدام Queues متعددة
في الأنظمة الكبيرة يتم تقسيم المهام إلى عدة Queues.
مثلاً:
- emails
- notifications
- imports
يمكن إرسال المهمة إلى Queue محددة:
SendWelcomeEmail::dispatch($user)->onQueue('emails');
وهذا يسمح بتخصيص workers لكل نوع من المهام.
متى يجب استخدام Queues
ليس كل شيء يحتاج Queue.
لكن هناك حالات واضحة يجب فيها استخدامه:
- إرسال البريد
- معالجة الصور
- استيراد البيانات
- التقارير الثقيلة
- تكاملات API البطيئة
هذه العمليات لا يجب أن تبطئ الطلب الأساسي.
الخلاصة
Queues في Laravel ليست مجرد ميزة إضافية، بل جزء أساسي في بناء تطبيقات قابلة للتوسع.
الفكرة الأساسية بسيطة:
- لا تنفذ العمليات الثقيلة داخل الطلب
- ادفعها إلى Queue
- دع Workers يتعاملون معها في الخلفية
بهذه الطريقة يصبح التطبيق أكثر استجابة، وأكثر قدرة على التعامل مع الأحمال العالية.