الفرق بين المراجعتين لصفحة: «Laravel/queues»

من موسوعة حسوب
لا ملخص تعديل
 
(19 مراجعة متوسطة بواسطة مستخدمين اثنين آخرين غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:طابور الانتظار}}</noinclude>
==مقدمة==
ملاحظة''':''' يوفر [[Laravel]] الآن Horizon، لوحة تحكم وضبط للأنظمة المدعومة من طوابير انتظار <code>Redis</code>. تفقد [[Laravel/horizon|توثيق Horizon]] لمزيد من المعلومات.


=== مقدمة ===
توفّر طوابير انتظار Laravel واجهة API موحدة بين مختلف طوابير انتظار البيئة الخلفية مثل Beanstalk أو Amazon SQS أو Redis أو قواعد البيانات العلائقية. تسمح ٌطوابير الانتظار بتأخير إنجاز المهام التي تتطلب الكثير من الوقت مثل إرسال بريد لوقت لاحق. تأخير هذه المهام يسرّع طلبات الويب في التطبيق بشكل كبير.
<u>ملاحظة</u>: يوفر Laravel الآن <code>Horizon</code>، لوحة تحكم وضبط للأنظمة المدعومة من طوابير انتظار <code>Redis</code>. تفقد توثيق Horison لمزيد من المعلومات.


توفّر طوابير انتظار Laravel واجهة API موحدة بين مختلف طوابير انتظار البيئة الخلفية مثل <code>Beanstalk</code> أو <code>Amazon SQS</code> أو <code>Redis</code> أو قواعد البيانات العلائقية. تسمح ٌطوابير الانتظار بتأخير إنجاز المهام التي تتطلب الكثير من الوقت مثل إرسال بريد لوقت لاحق. تأخير هذه المهام يسرّع طلبات الويب في التطبيق بشكل كبير.
يوجد ملف ضبط طوابير الانتظار في <code>config/queue.php</code>. ستجد في هذا الملف ضبط صلة كل طابور انتظار مضمّنة في الإطار. والتي تتضمن قاعدة بيانات Beanstalkd أو  Amazon SQS أو Redis ومشغل تزامني لتنفيذ المهام آنيًا (للاستعمال المحلي). يوجد أيضًا مشغل طوابير الانتظار <code>null</code> لتعطيل تنفيذ المهام المضافة للطابور.
 
===مقارنة الصلة مع طابور الانتظار===
يوجد ملف ضبط طوابير الانتظار في <code>config/queue.php</code>. ستجد في هذا الملف ضبط صلة كل طابور انتظار مضمّنة في الإطار. والتي تتضمن قاعدة بيانات <code>Beanstalkd</code> أو  <code>Amazon SQS</code> أو <code>Redis</code> ومشغل تزامني لتنفيذ المهام آنيًا (للاستعمال المحلي). يوجد أيضًا مشغل طوابير الانتظار <code>null</code> لتعطيل تنفيذ المهام المضافة للطابور.
 
==== مقارنة الصلة مع طابور الانتظار ====
قبل بدء العمل بطوابير انتظار Laravel، من المهم فهم الفرق بين طابور الانتظار "<code>queue</code>" والصلة "<code>connection</code>". يوجد في الملف <code>config/queue.php</code> خيار الضبط <code>connections</code>. يعرّف هذا الخيار صلة لخدمة خلفية مثل Amazon SQS أو Beanstalk أو Redis. لكن، يمكن أن تحتوي كل صلة على عدّة طوابير انتظار "queues" التي يمكن اعتبارها مكدس (stack) من المهام المنتظِرة.
قبل بدء العمل بطوابير انتظار Laravel، من المهم فهم الفرق بين طابور الانتظار "<code>queue</code>" والصلة "<code>connection</code>". يوجد في الملف <code>config/queue.php</code> خيار الضبط <code>connections</code>. يعرّف هذا الخيار صلة لخدمة خلفية مثل Amazon SQS أو Beanstalk أو Redis. لكن، يمكن أن تحتوي كل صلة على عدّة طوابير انتظار "queues" التي يمكن اعتبارها مكدس (stack) من المهام المنتظِرة.


لاحظ أنّ كل مثال ضبط صلة في ملف ضبط الطوابير يحتوي الخاصية queue. هذه هي للطابور الأولي التي تُرسَل له المهام عندما تُرسل للصلة المعيّنة. أي أنّك إن أرسلت مهمة دون تحديد أي طابور انتظار يجب استعمالها، فستُرسَل المهمّة للطابور المذكور في الخاصية queue في ضبط الصلة:<syntaxhighlight lang="php">
لاحظ أنّ كل مثال ضبط صلة في ملف ضبط الطوابير يحتوي الخاصية <code>queue</code>. هذه هي للطابور الأولي التي تُرسَل له المهام عندما تُرسل للصلة المعيّنة. أي أنّك إن أرسلت مهمة دون تحديد أي طابور انتظار يجب استعمالها، فستُرسَل المهمّة للطابور المذكور في الخاصية <code>queue</code> في ضبط الصلة:<syntaxhighlight lang="php">
// إرسال مهمة دون ذكر الطابور
// إرسال مهمة دون ذكر الطابور
  Job::dispatch();
  Job::dispatch();
سطر 19: سطر 16:




</syntaxhighlight>
</syntaxhighlight>قد لا تحتاج بعض التطبيقات لإرسال مهام لطوابير متعدد أبدًا بل تفضّل وجود طابور واحد. لكن يكون تعدد طوابير الانتظار مفيدًا للتطبيقات التي تريد إعطاء أولوية أو تقسيم معالجة المهام إذ تسمح عمّال Laravel بتحديد أي طابور انتظار يجب معالجتها و بأي أولوية. مثلًا، إذا أرسلت مهام لطابور الانتظار <code>high</code>، يمكنك إطلاق عامل بأولوية معالجة مرتفعة:<syntaxhighlight lang="php">
 
قد لا تحتاج بعض التطبيقات لإرسال مهام لطوابير متعدد أبدًا بل تفضّل وجود طابور واحد. لكن يكون تعدد طوابير الانتظار مفيدًا للتطبيقات التي تريد إعطاء أولوية أو تقسيم معالجة المهام إذ تسمح عمّال Laravel بتحديد أي طابور انتظار يجب معالجتها و بأي أولوية. مثلًا، إذا أرسلت مهام لطابور الانتظار <code>high</code>، يمكنك إطلاق عامل بأولوية معالجة مرتفعة:<syntaxhighlight lang="php">
php artisan queue:work --queue=high,default
php artisan queue:work --queue=high,default
</syntaxhighlight>
</syntaxhighlight>
 
===معلومات برنامج التشغيل و المتطلبات===
==== معلومات المشغل و المتطلبات ====
====Database====
===== قاعدة البيانات =====
لاستخدام برنامج تشغيل طوابير الانتظار database، ستحتاج إلى جدول في قاعدة البيانات ليحمل المهام. لتوليد ترحيل يصنع الجدول، نفّذ الأمر <code>queue:table</code>. بعد إنشاء الترحيل يمكنك تنفيذه باستعمال الأمر <code>migrate</code>:<syntaxhighlight lang="php">
لاستخدام مشغل طوابير الانتظار <code>database</code>، ستحتاج إلى جدول في قاعدة البيانات ليحمل المهام. لتوليد ترحيل يصنع الجدول، نفّذ الأمر <code>queue:table</code>. بعد إنشاء الترحيل يمكنك تنفيذه باستعمال الأمر <code>migrate</code>:<syntaxhighlight lang="php">
php artisan queue:table
php artisan queue:table


سطر 34: سطر 28:


</syntaxhighlight>
</syntaxhighlight>
 
====Redis====
===== Redis =====
لاستعمال برنامج تشغيل طوابير الانتظار Redis، يجب ضبط صلة قاعدة بيانات Redis في ملف الضبط <code>config/database.php</code>.
لاستعمال مشغّل طوابير الانتظار <code>Redis</code>، يجب ضبط صلة قاعدة بيانات <code>Redis</code> في ملف الضبط <code>config/database.php</code>.
=====Redis Cluster=====
 
إذا كانت صلة <code>Redis</code> تستعمل تجميعات Redis Cluster، يجب أن يحتوي اسم الطابور على مفتاح <code>hash tag</code>. هذا مطلوب للتأكد من أن كل المفاتيح المتوفّرة موجودة في نفس المكان:<syntaxhighlight lang="php">
====== Redis Cluster ======
إذا كانت صلة <code>Redis</code> تستعمل تجميعات Redis Cluster، يجب أن يحتوي اسم الطابور على مفتاح <code>hash tag</code>. هذا مطلوب للتأكد من أن كل المفاتيح المتوفّرة موجودة في نفس المكان:
<syntaxhighlight lang="php">
'redis' => [
'redis' => [


سطر 51: سطر 42:


</syntaxhighlight>
</syntaxhighlight>
=====الإيقاف=====
عند استعمال طوابير انتظار Redis، يمكن استعمال خيار الضبط <code>block_for</code> لتحديد المدة التي يجب أن ينتظرها المشغل لتصبح المهمة متوفرة قبل أن يواصل بقية العملة ويعيد سحب قاعدة بيانات Redis.


====== الإيقاف ======
قد يكون تعديل هذه القيمة حسب حجم طابور الانتظار  أكثر فاعلية من السحب المتواصل لمهام جديدة من قاعدة بيانات  Redis. يمكنك مثلا إعطاؤها القيمة 5 لإيقاف المشغل 5 ثوان في حين ينتظر أن تصبح المهمة متوفرة:<syntaxhighlight lang="php">
عند استعمال طوابير انتظار Redis، يمكن استعمال خيار الضبط <code>block_for</code> لتحديد المدة التي يجب أن ينتظرها المشغل لتصبح المهمة متوفرة قبل أن يواصل بقية العملة ويعيد سحب قاعدة بيانات Redis.
قد يكون تعديل هذه القيمة حسب حجم طابور الانتظار  أكثر فاعلية من السحب المتواصل لمهام جديدة من قاعدة بيانات  Redis. يمكنك مثلا إعطاؤها القيمة 5 لإيقاف المشغل 5 ثوان في حين ينتظر أن تصبح المهمة متوفرة:
<syntaxhighlight lang="php">
'redis' => [
'redis' => [


سطر 66: سطر 56:




</syntaxhighlight>
</syntaxhighlight>'''تنبيه:''' Blocking pop هي خاصية تجريبية. يوجد إمكانية بسيطة بأن تضيع مهمة في خادم Redis أو أن يتوقف عامل عن العمل وقت استرجاع المهمة.
<u>تنبيه</u>: Blocking pop هي خاصية تجريبية. يوجد إمكانية بسيطة بأن تضيع مهمة في خادم Redis أو أن يتوقف عامل عن العمل وقت استرجاع المهمة.
====متطلبات برامج تشغيل أخرى====
 
تحتاج التبعيات التالية لبرامج التشغيل المذكورة:
===== متطلبات مشغلات أخرى =====
*Amazon SQS: aws/aws-sdk-php ~3.0
تحتاج التبعيات التالية للمشغلات المذكورة
*Beanstalkd: pda/pheanstalk ~3.0
* Amazon SQS: aws/aws-sdk-php ~3.0
*Redis: predis/predis ~1.0
* Beanstalkd: pda/pheanstalk ~3.0
==إنشاء المهام==
* Redis: predis/predis ~1.0
===توليد أصناف المهام===
 
=== صنع المهام ===
 
==== توليد أصناف المهام ====
في العادة، توجد كل المهام التي يمكن إضافتها لطوابير الانتظار في المجلد <code>app/Jobs</code>. إذا لم يكن المجلد موجودًا فسينشَأ عند تنفيذ الأمر <code>make:job</code>. يمكنك إحداث مهمّة جديدة باستخدام سطر الأوامر:<syntaxhighlight lang="php">
في العادة، توجد كل المهام التي يمكن إضافتها لطوابير الانتظار في المجلد <code>app/Jobs</code>. إذا لم يكن المجلد موجودًا فسينشَأ عند تنفيذ الأمر <code>make:job</code>. يمكنك إحداث مهمّة جديدة باستخدام سطر الأوامر:<syntaxhighlight lang="php">
php artisan make:job ProcessPodcast  
php artisan make:job ProcessPodcast  
</syntaxhighlight>
</syntaxhighlight>سيُنفّذ الصنفُ المُنشَأ الواجهةَ <code>Illuminate\Contracts\Queue\ShouldQueue</code>، ويُعلم Laravel أنّ المهمة يجب أن تضاف لقامة انتظار وتُنفّذ بطريقة غير متزامنة.
 
===هيكلة الصنف===
سيُنفّذ الصنفُ المُنشَأ الواجهةَ <code>Illuminate\Contracts\Queue\ShouldQueue</code>، ويُعلم Laravel أنّ المهمة يجب أن تضاف لقامة انتظار وتُنفّذ بطريقة غير متزامنة.
 
==== هيكلة الصنف ====
أصناف المهام بسيطة، تحتوي في العادة فقط على التابع <code>handle</code> الذي ينادَى عند معالجة المهمّة من قبل طابور الانتظار. للبدء، لنلق نظرة على مثال صنف مهمة. في هذا المثال، سنتظاهر بإدارة خدمة نشر تدوين صوتي و نحتاج لمعالجة الملفات المرفوعة قبل نشرها:<syntaxhighlight lang="php">
أصناف المهام بسيطة، تحتوي في العادة فقط على التابع <code>handle</code> الذي ينادَى عند معالجة المهمّة من قبل طابور الانتظار. للبدء، لنلق نظرة على مثال صنف مهمة. في هذا المثال، سنتظاهر بإدارة خدمة نشر تدوين صوتي و نحتاج لمعالجة الملفات المرفوعة قبل نشرها:<syntaxhighlight lang="php">
<?php
<?php
سطر 97: سطر 80:
   protected $podcast;
   protected $podcast;
   /**
   /**
     * صناعة المهمة
     * إنشاء المهمة
     *
     *
     * @param  Podcast  $podcast
     * @param  Podcast  $podcast
سطر 119: سطر 102:




</syntaxhighlight>
</syntaxhighlight>في هذا المثال، لاحظ أنه يمكننا تمرير نموذج <code>Eloquent</code> مباشرة للتابع الباني للمهمة. بسبب الخاصية  <code>SerializeModels</code> التي تستعملها المهمة، تكون نماذج <code>Eloquent</code> متسلسلة أو غير متسلسلة بلباقة عند معالجة المهمّة. إذا كانت المهمّة المنتظِرة تقبل نموذجًا في التابع الباني، ستتم سلسلة معرّف النموذج فقط في طابور الانتظار. عند التعامل الفعلي مع المهمة، يسترجع النظام تلقائيًا كامل النموذج من قاعدة البيانات. كل هذا واضح للتطبيق ويوقف المشاكل التي يمكن أن تحصل من سلسلة كامل النموذج.
 
في هذا المثال، لاحظ أنه يمكننا تمرير نموذج <code>Eloquent</code> مباشرة للتابع الباني للمهمة. بسبب الخاصية  <code>SerializeModels</code> التي تستعملها المهمة، تكون نماذج <code>Eloquent</code> متسلسلة أو غير متسلسلة بلباقة عند معالجة المهمّة. إذا كانت المهمّة المنتظِرة تقبل نموذجًا في التابع الباني، ستتم سلسلة معرّف النموذج فقط في طابور الانتظار. عند التعامل الفعلي مع المهمة، يسترجع النظام تلقائيًا كامل النموذج من قاعدة البيانات. كل هذا واضح للتطبيق ويوقف المشاكل التي يمكن أن تحصل من سلسلة كامل النموذج.


يُنادى التابع <code>handle</code> عند معالجة المهمة من قبل طابور الانتظار. لاحظ أنّه يمكنك تقريب أنواع التبعيات في التابع <code>handle</code>. يضيف حاوي خدمات Laravel تلقائيا هذه التبعيات.
يُنادى التابع <code>handle</code> عند معالجة المهمة من قبل طابور الانتظار. لاحظ أنّه يمكنك تقريب أنواع التبعيات في التابع <code>handle</code>. يضيف حاوي خدمات Laravel تلقائيا هذه التبعيات.


<u>تنبيه</u>: يجب أن تمرّر البيانات الثنائية (binary) مثل الصور الخام عبر الدالة <code>ase64_encode</code> قبل تمريرها لمهمة منتظِرة وإلّا قد لا تتم سَلسلتها لشيفرة <code>JSON</code> بطريقة صحيحة عند إضافتها لطابور الانتظار.
<u>تنبيه</u>: يجب أن تمرّر البيانات الثنائية (binary) مثل الصور الخام عبر الدالة <code>ase64_encode</code> قبل تمريرها لمهمة منتظِرة وإلّا قد لا تتم سَلسلتها لشيفرة <code>JSON</code> بطريقة صحيحة عند إضافتها لطابور الانتظار.
 
==إرسال المهام==
=== إرسال المهام ===
بعد كتابة صنف المهمة، يمكنك ارسالها باستعمال التابع <code>dispatch</code> على المهمة نفسها. المعاملات الممررة للتابع <code>dispatch</code> ستمرّر للتابع الباني للمهمة:<syntaxhighlight lang="php">
بعد كتابة صنف المهمة، يمكنك ارسالها باستعمال التابع <code>dispatch</code> على المهمة نفسها. المعاملات الممررة للتابع <code>dispatch</code> ستمرّر للتابع الباني للمهمة:
<syntaxhighlight lang="php">
<?php
<?php


سطر 139: سطر 118:


   /**
   /**
     * Store a new podcast.
     * حفظ تدوينة جديدة
     *
     *
     * @param  Request  $request
     * @param  Request  $request
سطر 153: سطر 132:


</syntaxhighlight>
</syntaxhighlight>
 
===الإرسال المتأخر===
==== الإرسال المتأخر ====
إذا أردت تأخير تنفيذ مهمّة في طابور الانتظار، يمكنك استعمال التابع <code>delay</code> عند إرسال المهمّة. مثلًا، لنحدد أن المهمة يجب ألّا تكون متوافرة إلا بعد 10 دقائق بعد إرسالها:<syntaxhighlight lang="php">
إذا أردت تأخير تنفيذ مهمّة في طابور الانتظار، يمكنك استعمال التابع <code>delay</code> عند إرسال المهمّة. مثلًا، لنحدد أن المهمة يجب ألّا تكون متوافرة إلا بعد 10 دقائق بعد إرسالها:<syntaxhighlight lang="php">
<?php
<?php
سطر 179: سطر 157:




</syntaxhighlight>
</syntaxhighlight><u>تنبيه</u>: خدمة Amazon SQS لديها حد تأخير أقصى يساوي 15 دقيقة.
 
===تسلسل المهام===
<u>تنبيه</u>: خدمة Amazon SQS لديها حد تأخير أقصى يساوي 15 دقيقة.
 
==== تسلسل المهام ====
يسمح تسلسل المهام بتحديد مجموعة من المهام التي يجب تنفيذها بالتسلسل. إذا فشل تنفيذ أحد المهام، فلن تُنفَّذ البقية. لتنفيذ سلسلة مهام، يمكن استخدام التابع <code>withChain</code> على أي مهمة قابلة للإرسال:<syntaxhighlight lang="php">
يسمح تسلسل المهام بتحديد مجموعة من المهام التي يجب تنفيذها بالتسلسل. إذا فشل تنفيذ أحد المهام، فلن تُنفَّذ البقية. لتنفيذ سلسلة مهام، يمكن استخدام التابع <code>withChain</code> على أي مهمة قابلة للإرسال:<syntaxhighlight lang="php">
ProcessPodcast::withChain([
ProcessPodcast::withChain([
سطر 193: سطر 168:


</syntaxhighlight>
</syntaxhighlight>
 
====اتصال السلسلة وطابور الانتظار====
===== صلة السلسلة وقائمتها =====
إذا أردت تعريف اتصال وطابور انتظار أولي لسلسلة المهام، يمكن استعمال التابعين <code>allOnConnection</code> و <code>allOnQueue</code>. يحدد هذان التابعان الاتصال و طابور الانتظار الواجب استعمالها في حالة عدم تحديد الاتصال و طابور الانتظار فعليا:<syntaxhighlight lang="php">
إذا أردت تعريف صلة و طابور انتظار أولي لسلسلة المهام، يمكن استعمال التابعين <code>allOnConnection</code> و <code>allOnQueue</code>. يحدد هذان التابعان الصلة و طابور الانتظار التي يجب استعماله في حالة عدم تحديد الصلة و طابور الانتظار فعليا:<syntaxhighlight lang="php">
ProcessPodcast::withChain([
ProcessPodcast::withChain([


سطر 204: سطر 178:


</syntaxhighlight>
</syntaxhighlight>
===تخصيص الصلة و طابور الانتظار===


==== تخصيص الصلة و طابور الانتظار ====
==== الإرسال لطابور انتظار معين ====
الإرسال لطابور انتظار معين
بإرسال المهام لطوابير مختلفة، يمكنك تصنيف المهام وحتى إعطاء أولوية لعدد العملة المرفقة بكل طابور انتظار. تذكر أنّ هذا لا يُرسل المهام لصلات مختلفة كما عُرِّفت في ملف الضبط، بل فقط لطوابير معيّنة في صلة واحدة. لتخصيص صلة مغيرة، استعمل التابع <code>onQueue</code> عند إرسال المهمّة:<syntaxhighlight lang="php">
بإرسال المهام لطوابير مختلفة، يمكنك تصنيف المهام وحتى إعطاء أولوية لعدد العملة المرفقة بكل طابور انتظار. تذكر أنّ هذا لا يُرسل المهام لصلات مختلفة كما عُرِّفت في ملف الضبط، بل فقط لطوابير معيّنة في صلة واحدة. لتخصيص صلة مغيرة، استعمل التابع <code>onQueue</code> عند إرسال المهمّة:
<syntaxhighlight lang="php">
<?php
<?php


سطر 218: سطر 191:


   /**
   /**
     * Store a new podcast.
     * حفظ تدوينة جديدة
     *
     *
     * @param  Request  $request
     * @param  Request  $request
سطر 233: سطر 206:
</syntaxhighlight>
</syntaxhighlight>


بالطبع يمكنك سَلسلة <code>onConnection</code> و <code>onQueue</code> لتخصيص الصلة و الطابور:<syntaxhighlight lang="php">
==== الإرسال لاتصال معيّن ====
في حال كنت تتعامل مع اتصالات طوابير انتظا مختلفة، يمكنك تحديد الاتصال لإرسال مهمّة ما وذلك باستخدام التابع <code>onConnection</code>:<syntaxhighlight lang="php">
<?php
 
namespace App\Http\Controllers;
 
use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
 
class PodcastController extends Controller
{
    /**
    * حفظ تدوينة جديدة
    *
    * @param  Request  $request
    * @return Response
    */
    public function store(Request $request)
    {
        // إنشاء تدوينة
 
        ProcessPodcast::dispatch($podcast)->onConnection('sqs');
    }
}
</syntaxhighlight>بالطبع يمكنك سَلسلة <code>onConnection</code> و <code>onQueue</code> لتخصيص الصلة و الطابور:<syntaxhighlight lang="php">
ProcessPodcast::dispatch($podcast)
ProcessPodcast::dispatch($podcast)


سطر 240: سطر 238:


</syntaxhighlight>
</syntaxhighlight>
 
===تحديد العدد الأقصى للمحاولات ومدة الانتظار===
==== تحديد العدد الأقصى للمحاولات ومدة الانتظار ====
====الحد الأقصى للمحاولات====
 
===== الحد الأقصى للمحاولات =====
إحدى الطرائق لتحديد العدد الأقصى للمحاولات تنفيذ مهمّة هي استعمال الخيار <code>tries--</code> مع أمر artisan:<syntaxhighlight lang="php">
إحدى الطرائق لتحديد العدد الأقصى للمحاولات تنفيذ مهمّة هي استعمال الخيار <code>tries--</code> مع أمر artisan:<syntaxhighlight lang="php">
php artisan queue:work --tries=3  
php artisan queue:work --tries=3  
</syntaxhighlight>
</syntaxhighlight>لكن يمكنك اتخاذ طريقة عمل أكثر حُبيبية بتعريف العدد الأقصى للمحاولات في صنف المهمة نفسه. إذا كان العدد الأقصى محددًا في صنف المهمة، ستأخذ أولية على القيمة المحددة في سطر الأوامر:<syntaxhighlight lang="php">
 
لكن يمكنك اتخاذ طريقة عمل أكثر حُبيبية بتعريف العدد الأقصى للمحاولات في صنف المهمة نفسه. إذا كان العدد الأقصى محددًا في صنف المهمة، ستأخذ أولية على القيمة المحددة في سطر الأوامر:<syntaxhighlight lang="php">
<?php
<?php


سطر 265: سطر 259:


</syntaxhighlight>
</syntaxhighlight>
 
====المحاولات على أساس الوقت====
===== المحاولات الطابور على أساس الوقت =====
كبديل لتحديد العدد الأقصى لمحاولات تنفيذ مهمة قبل إعلان فاشلها، يمكن تحديد الوقت الذي تفشل المهمة إذا تجاوزته. يسمح هذا للمهمة بمحاولة التنفيذ أي عدد من المرات في الوقت المحدد. لتعريف المدة الانتظار، أضف التابع <code>retryUntil</code> لصنف المهمة:<syntaxhighlight lang="php">
كبديل لتحديد العدد الأقصى لمحاولات تنفيذ مهمة قبل إعلانها فاشلة، يمكن تحديد الوقت الذي تفشل المهمة إذا تجاوزته. يسمح هذا للمهمة بمحاولة التنفيذ أي عدد من المرات في الوقت المحدد. لتعريف المدة الانتظار، أضف التابع <code>retryUntil</code> لصنف المهمة:<syntaxhighlight lang="php">
/**
/**


سطر 280: سطر 273:




</syntaxhighlight>
</syntaxhighlight>ملاحظة: يمكنك أيضًا تعريف <code>retryUntil</code> في مستمع أحداث الإضافة لطابور الانتظار.
<u>ملاحظة</u>: يمكنك أيضًا تعريف <code>retryUntil</code> في مستمع أحداث الإضافة لطابور الانتظار.  
====نفاذ الوقت Timeout====
 
'''تنبيه:''' الخاصية <code>timeout</code> تعمل بطريقة أمثل مع PHP 7.1+‎ والإضافة pcntl.
===== Timeout =====
<u>تنبيه</u>: الخاصية <code>timeout</code> تعمل بطريقة أمثل مع PHP 7.1+‎ والإضافة pcntl.


يمكن أيضًا تحديد عدد ثواني الانتظار باستخدام الخيار <code>timeout</code> مع أمر artisan:<syntaxhighlight lang="php">
يمكن أيضًا تحديد عدد ثواني الانتظار باستخدام الخيار <code>timeout</code> مع أمر artisan:<syntaxhighlight lang="php">
php artisan queue:work --timeout=30  
php artisan queue:work --timeout=30  
</syntaxhighlight>
</syntaxhighlight>لكن، يمكن أيضًا تحديد عدد ثواني الانتظار في صنف المهمة نفسه. إذا حُدد <code>timeout</code> في صنف المهمة تكون له الأولوية على القيمة المحددة في سطر الأوامر:<syntaxhighlight lang="php">
 
لكن، يمكن أيضًا تحديد عدد ثواني الانتظار في صنف المهمة نفسه. إذا حُدد <code>timeout</code> في صنف المهمة تكون له الأولوية على القيمة المحددة في سطر الأوامر:
<syntaxhighlight lang="php">
<?php
<?php


سطر 308: سطر 296:


</syntaxhighlight>
</syntaxhighlight>
===تحديد معدل التنفيذ===
'''تنبيه:''' تتطلب هذه الخاصية أن يتعامل التطبيق مع خادم <code>Redis</code>.


==== تحديد معدل التنفيذ ====
إذا كان التطبيق يتعامل مع خادم Redis، يمكنك ترتيب المهام المنتظِرة حسب الوقت أو التنافسية. تساعد هذه الخاصية خاصة عندما تتعامل المهام مع واجهات API هي أيضًا محدودة. مثلًا، باستخدام التابع <code>throttle</code>، يمكنك تحديد أن لا يتجاوز تنفيذ نوع معين من المهام 10 مرات كل 60 ثانية. إذا كان الحصول على قفلٍ غيرُ ممكنٍ، يمكنك تحرير المهمة لتعاد محاولة تنفيذها لاحقًا:<syntaxhighlight lang="php">
<u>تنبيه</u>: تتطلب هذه الخاصية أن يتعامل التطبيق مع خادم <code>Redis</code>.
Redis::throttle('key')->allow(10)->every(60)->then(function () {


إذا كان التطبيق يتعامل مع خادم Redis، يمكنك ترتيب المهام المنتظِرة حسب الوقت أو التنافسية. تساعد هذه الخاصية خاصة عندما تتعامل المهام مع واجهات API هي أيضًا محدودة. مثلًا، باستخدام التابع throttle، يمكنك تحديد أن لا يتجاوز تنفيذ نوع معين من المهام 10 مرات كل 60 ثانية. إذا كان الحصول على قفلٍ غيرُ ممكنٍ، يمكنك تحرير المهمة لتعاد محاولة تنفيذها لاحقًا:
  // Job logic...
Redis::throttle('key')->allow(10)->every(60)->then(function () {
  // Job logic...
}, function () {
}, function () {
  // لا يمكن الحصول على قفل..


    return $this->release(10);
  // لا يمكن الحصول على قفل..
  return $this->release(10);
});
});
ملاحظة: في المثال السابق، يمكن أن تكون قيمة key أي سلسلة حروف تعرف بصفة فريدة نوع المهمة تريد تحديد معدّل تنفيذها. مثلًا، قد تريد صناعة المفتاح باستخدام اسم صنف المهمة  ومعرّف النموذج الذي تعمل عليه.


بدل ذلك، يمكنك تحديد العدد الأقصى للعمّال المتوازين على نفس المهمة. تكون هذه الخاصية مفيدة عند العمل مع موارد لا تقبل أكثر من مهمة واحدة في الوقت. مثلاً، استخدم التابع funnel لتحديد نوع المهام التي يجب تنفيذها من قبل عامل واحد:
 
</syntaxhighlight>'''ملاحظة:''' في المثال السابق، يمكن أن تكون قيمة <code>key</code> أي سلسلة حروف تعرف بصفة فريدة نوع المهمة تريد تحديد معدّل تنفيذها. مثلًا، قد تريد صناعة المفتاح باستخدام اسم صنف المهمة  ومعرّف النموذج الذي تعمل عليه.
 
بدل ذلك، يمكنك تحديد العدد الأقصى للعمّال المتوازين على نفس المهمة. تكون هذه الخاصية مفيدة عند العمل مع موارد لا تقبل أكثر من مهمة واحدة في الوقت. مثلاً، استخدم التابع <code>funnel</code> لتحديد نوع المهام التي يجب تنفيذها من قبل عامل واحد:<syntaxhighlight lang="php">
Redis::funnel('key')->limit(1)->then(function () {
Redis::funnel('key')->limit(1)->then(function () {
  // Job logic...
 
  // Job logic...
}, function () {
}, function () {
  // Could not obtain lock...


    return $this->release(10);
  // Could not obtain lock...
  return $this->release(10);
});
});
ملاحظة: عند استعمال تحديد التنفيذ، قد يكون من الصعب تحديد عدد المحاولات اللازمة لإنجاح المهمة بدقة. لذلك من المفيد دمج تحديد التنفيذ مع المحاولات المقيدة بوقت.
 
التعامل مع الأخطاء
 
إذا أُطلق استثناء حين معالجة المهمّة، تُطلق المهمة تلقائيًا لطابور الانتظار لتتم محاولة إعادة تنفيذها لاحقا. تبقى المهمة في حالة إطلاق حتى تصل للحد الأقصة المسموح من المحاولات. يُحدَّد العدد الأقصى للمحولات باستعمال الخيار tries-- مع الأمر queue:work. يمكن أيضًا تحديد الحد الأقصى للمحاولات في صنف المهمة. المزيد من المعلومات عن تشغيل عمّال الطوابير فيما يلي.
</syntaxhighlight>ملاحظة: عند استعمال تحديد التنفيذ، قد يكون من الصعب تحديد عدد المحاولات اللازمة لإنجاح المهمة بدقة. لذلك من المفيد دمج تحديد التنفيذ مع المحاولات المقيدة بوقت.
تشغيل عمّال الطابور
===التعامل مع الأخطاء===
يتضمّن Laravel عامل طوابير انتظار يعالج المهم الجديدة عند دفعها للطابور. يمكن تشغيل عامل بتنفيذ الأمر queue:work. لاحظ أنّه عند بدء الأمر، سيواصل العمل إلى أن يتم إيقافه يدويًا أو إغلاق الطرفية:
إذا أُطلق استثناء حين معالجة المهمّة، تُطلق المهمة تلقائيًا لطابور الانتظار لتتم محاولة إعادة تنفيذها لاحقا. تبقى المهمة في حالة إطلاق حتى تصل للحد الأقصة المسموح من المحاولات. يُحدَّد العدد الأقصى للمحولات باستعمال الخيار <code>tries--</code> مع الأمر <code>queue:work</code>. يمكن أيضًا تحديد الحد الأقصى للمحاولات في صنف المهمة. المزيد من المعلومات عن تشغيل عمّال الطوابير فيما يلي.
==تشغيل عمّال الطابور==
يتضمّن [[Laravel]] عامل طوابير انتظار يعالج المهم الجديدة عند دفعها للطابور. يمكن تشغيل عامل بتنفيذ الأمر <code>queue:work</code>. لاحظ أنّه عند بدء الأمر، سيواصل العمل إلى أن يتم إيقافه يدويًا أو إغلاق الطرفية:<syntaxhighlight lang="php">
php artisan queue:work
php artisan queue:work
ملاحظة: لإبقاء معالج الأمر queue:work يعمل بطريقة دائمة في الخلفية، يجب عليك استخدام مراقب معالجات مثل supervisor للتأكد من أن المعالج لم يتوقف فجأة.
</syntaxhighlight>ملاحظة: لإبقاء معالج الأمر <code>queue:work</code> يعمل بطريقة دائمة في الخلفية، يجب عليك استخدام مراقب معالجات مثل supervisor للتأكد من أن المعالج لم يتوقف فجأة. تذكر أن العمّال معالجاتٌ تعيش طويلًا وتسجّل حالة التطبيق في الذاكرة و بالتالي لن تلاحظ أي تغيير في التطبيق بعد إطلاقها، لذا تأكد من إعادة إطلاقها بعد نشر التطبيق.
تذكر أن العمّال معالجاتٌ تعيش طويلًا وتسجّل حالة التطبيق في الذاكرة و بالتالي لن تلاحظ أي تغيير في التطبيق بعد إطلاقها، لذا تأكد من إعادة إطلاقها بعد نشر التطبيق.
===معالجة مهمة واحدة===
معالجة مهمة واحدة
يُستعمل الخيار <code>once--</code> لإخبار العامل بمعالجة مهمة واحدة من طابور الانتظار:<syntaxhighlight lang="php">
يُستعمل الخيار once-- لإخبار العامل بمعالجة مهمة واحدة من طابور الانتظار:
php artisan queue:work --once
php artisan queue:work --once
تخصيص صلة وطابور انتظار
</syntaxhighlight>
يمكنك تحديد أي صلة على العامل استخدامها. يجب أن يتوافق اسم الصلة الممرّر للأمر work مع إحدى الصّلات المعرفة في ملف الضبط config/queue.php:
====تخصيص اتصال وطابور انتظار====
php artisan queue:work redis
يمكنك تحديد أي اتصال على العامل استخدامه. يجب أن يتوافق اسم الاتصال الممرّر للأمر <code>work</code> مع إحدى الصّلات المعرفة في ملف الضبط <code>config/queue.php</code>:<syntaxhighlight lang="php">
يمكنك تخصيص العامل أكثر عبر معالجة طوابير معيّنة فقط من الصلة. مثلًا، إذا كانت كل رسائل البريد الإلكتروني تُعالَج في طابور انتظار واحد emails من الصلة redis، يمكنك إطلاق عامل يعالج فقط ذلك الطابور باستعمال الأمر التالي:
php artisan queue:work redis  
</syntaxhighlight>يمكنك تخصيص العامل أكثر عبر معالجة طوابير معيّنة فقط من الاتصال. مثلًا، إذا كانت كل رسائل البريد الإلكتروني تُعالَج في طابور انتظار واحد <code>emails</code> من الصلة <code>redis</code>، يمكنك إطلاق عامل يعالج فقط ذلك الطابور باستعمال الأمر التالي:<syntaxhighlight lang="php">
php artisan queue:work redis --queue=emails
php artisan queue:work redis --queue=emails
مراعاة الموارد
</syntaxhighlight>
عاملوا طوابير الانتظار في الخلفية لا تُعيد إقلاع الإطار قبل معالجة كل مهمة، لذا يجب عليك تحرير أي موارد ثقيلة بعد انتهاء كل مهمة. لو كنت مثلا تعمل على معالجة الصور باستعمال المكتبة GD، يجب عليك تحرير الذاكرة باستخدام الدالة imagedestroy عند الإنتهاء.
====مراعاة الموارد====
أولويات طوابير الانتظار
عاملوا طوابير الانتظار في الخلفية لا تُعيد إقلاع الإطار قبل معالجة كل مهمة، لذا يجب عليك تحرير أي موارد ثقيلة بعد انتهاء كل مهمة. لو كنت مثلا تعمل على معالجة الصور باستعمال المكتبة <code>GD</code>، يجب عليك تحرير الذاكرة باستخدام الدالة <code>imagedestroy</code> عند الإنتهاء.
قد تريد في بعض الأحيان إعطاء أولوية لمعالجة طوابير الانتظار. مثلًا، في ملف الضبط config/queue.php يمكنك أن أن تضبط الطابور الأولي للصلة redis بالقيمة low لكن فد تريد في بعض الأحيان إضافة مهمة لطابور أعلى أولوية high كالآتي:
===أولويات طوابير الانتظار===
قد تريد في بعض الأحيان إعطاء أولوية لمعالجة طوابير الانتظار. مثلًا، في ملف الضبط <code>config/queue.php</code> يمكنك أن أن تضبط الطابور الأولي للصلة <code>redis</code> بالقيمة <code>low</code> لكن فد تريد في بعض الأحيان إضافة مهمة لطابور أعلى أولوية <code>high</code> كالآتي:<syntaxhighlight lang="php">
dispatch((new Job)->onQueue('high'));
dispatch((new Job)->onQueue('high'));
لإطلاق عامل يتثبت من أن كل المهام ذات أولوية مرتفعة high  قد عولجت قبل المواصلة لبقية المهام low، مرّر لائحة من أسماء طوابير الانتظار مفرّقف بفاصلة ',' إلى الأمر work:
</syntaxhighlight>لإطلاق عامل يتثبت من أن كل المهام ذات أولوية مرتفعة <code>high</code> قد عولجت قبل المواصلة لبقية المهام <code>low</code>، مرّر لائحة من أسماء طوابير الانتظار مفرّقف بفاصلة ',' إلى الأمر <code>work</code>:<syntaxhighlight lang="php">
php artisan queue:work --queue=high,low
php artisan queue:work --queue=high,low
عملة طوابير الانتظار
</syntaxhighlight>
حيث أن العمّال معالجات تعيش طويلا، لن تلاحظا تغييرات في الشيفرة إن لم تتم إعادة إطلاقها. لذا، الطريقة الأسهل نشر تطبيق يستعمل عمّال الطوابير هي إعادة إطلاق العمّال في عملية النشر. يمكنك إعادة نشر العمال بسهولة باستخدام الأمر queue:restart:
===عملة طوابير الانتظار والنشر على الخادم الإنتاجي===
php artisan queue:restart
حيث أن العمّال معالجات تعيش طويلا، لن تلاحظ تغييرات في الشيفرة إن لم تتم إعادة إطلاقها. لذا، الطريقة الأسهل نشر تطبيق يستعمل عمّال الطوابير هي إعادة إطلاق العمّال في عملية النشر. يمكنك إعادة نشر العمال بسهولة باستخدام الأمر <code>queue:restart</code>:<syntaxhighlight lang="php">
سيطلب هذا الأمر من العمال جميعًا الإنتهاء بعد إنهاء المهمة الحالية حتى لا تضيع أي مهمة موجودة. حيث سينتهي العمال الموجودون بعد الأمر queue:restart، يجب أن تملك مراقب معالجات مثل Supervisor ليعيد إطلاقهم آليًا.
php artisan queue:restart  
ملاحظة: تستعمل طوابير الانتظار التخزين المؤقت cache لحفظ إشارة إعادة الإطلاق، لذا يجب عليك التأكد من ضبط مشغل تخزين مؤقت قبل استخدام هذه الخاصية.
</syntaxhighlight>سيطلب هذا الأمر من العمال جميعًا الانتهاء بعد إنهاء المهمة الحالية حتى لا تضيع أي مهمة موجودة. حيث سينتهي العمال الموجودون بعد الأمر <code>queue:restart</code>، يجب أن تملك مراقب معالجات مثل Supervisor ليعيد إطلاقهم آليًا.  
صلاحية المهام و نفاذ الوقت
إنتهاء صلاحية المهام
في ملف config/queue.php، تعرّف كل صلة الخيار retry_after. يحدّد هذا الخيار عدد الثواني الذي يجب أن تنتظرها الصلة قبل محاولة إعادة تنفيذ مهمة تتم معالجتها. مثلًا، إن كانت قيمة retry_after تساوي 90، تُعاد المهمة للطابور إذا تمت معالجتها لمدة 90 ثانية دون حذفها. في العادة، يجب ضبط قيمة retry_after للمدة المعقولة التي تستغرقها المهمة لإكمال المعالجة.


تنبيه: الصلة الوحيدة التي لا تتضمن retry_after هي Amazon SQS. يعيد SQS محاولة التنفيذ حسب الوقت المبدئي للرؤية الذي يحدد في سطر أوامر AWS.
'''ملاحظة''': تستعمل طوابير الانتظار التخزين المؤقت cache لحفظ إشارة إعادة الإطلاق، لذا يجب عليك التأكد من ضبط مشغل تخزين مؤقت قبل استخدام هذه الخاصية.
===صلاحية المهام ونفاذ الوقت===
====إنتهاء صلاحية المهام====
في ملف <code>config/queue.php</code>، تعرّف كل صلة الخيار <code>retry_after</code>. يحدّد هذا الخيار عدد الثواني الذي يجب أن تنتظرها الصلة قبل محاولة إعادة تنفيذ مهمة تتم معالجتها. مثلًا، إن كانت قيمة <code>retry_after</code> تساوي 90، تُعاد المهمة للطابور إذا تمت معالجتها لمدة 90 ثانية دون حذفها. في العادة، يجب ضبط قيمة <code>retry_after</code> للمدة المعقولة التي تستغرقها المهمة لإكمال المعالجة.


وقت نفاد العامل
<u>تنبيه</u>: الصلة الوحيدة التي لا تتضمن <code>retry_after</code> هي Amazon SQS. يعيد SQS محاولة التنفيذ حسب الوقت المبدئي للرؤية الذي يحدد في سطر أوامر AWS.
يملك الأمر queue:work الخيار timeout--. يحدد هذا الخيار المدة التي ينتظرها المعالج الرئيسي لطوابير الانتظار في Laravel قبل أن ينهي عامل طابور انتظار فرعية بصدد معالجة مهمة. في بعض الأحيان، يصبح عامل إحدى الطوابير الفرعية متجمّدا "frozen" لعدة أسباب، كنداء HTTP خارجي غير متجاوب. يحذف الخيار timeout-- المعالجات المتجمدة التي تتجاوز المدة المحددة في الخيار:
====وقت نفاذ العامل====
يملك الأمر <code>queue:work</code> الخيار <code>timeout--</code>. يحدد هذا الخيار المدة التي ينتظرها المعالج الرئيسي لطوابير الانتظار في Laravel قبل أن ينهي عامل طابور انتظار فرعية بصدد معالجة مهمة. في بعض الأحيان، يصبح عامل إحدى الطوابير الفرعية متجمّدا "frozen" لعدة أسباب، كنداء HTTP خارجي غير متجاوب. يحذف الخيار timeout-- المعالجات المتجمدة التي تتجاوز المدة المحددة في الخيار:<syntaxhighlight lang="php">
php artisan queue:work --timeout=60
php artisan queue:work --timeout=60
خيار الضبط retry_after وخيار الأمر timeout-- مختلفان، لكن يعملان معًا للتأكد من أن المهمة لا تضيع ولا تعالج بطريقة ناجحة إلا مرّة واحدة.
</syntaxhighlight>خيار الضبط <code>retry_after</code> وخيار الأمر <code>timeout--</code> مختلفان، لكن يعملان معًا للتأكد من أن المهمة لا تضيع ولا تعالج بطريقة ناجحة إلا مرّة واحدة.
تنبيه: قيمة timeout-- يجب أن تكون دومًا أقصر بعدّة ثواني على الأقل من قيمة retry_after. سيضمن هذا أن العامل الذي يعالج مهمة معينة ينتهي قبل إعادة محاولة المهمة. إذا كانت مدة timeout-- أطول من retry_after قد تتم معالجة المهمة مرتين.
 
مدة نوم العامل
'''تنبيه''': قيمة <code>timeout--</code> يجب أن تكون دومًا أقصر بعدّة ثواني على الأقل من قيمة <code>retry_after</code>. سيضمن هذا أن العامل الذي يعالج مهمة معينة ينتهي قبل إعادة محاولة المهمة. إذا كانت مدة <code>timeout--</code> أطول من <code>retry_after</code> قد تتم معالجة المهمة مرتين.
عندما تتوفر مهام في طابور الانتظار يواصل العامل العمل دون تأخير بينها. لكن، يحدد الخيار sleep مدة نوم العامل (بالثواني) في حالة عدم وجود مهام متوفرة. عند نومه، لن يعالج العامل أي مهام حتى يستيقظ مجددًا:
====مدة نوم العامل====
عندما تتوفر مهام في طابور الانتظار يواصل العامل العمل دون تأخير بينها. لكن، يحدد الخيار <code>sleep</code> مدة نوم العامل (بالثواني) في حالة عدم وجود مهام متوفرة. عند نومه، لن يعالج العامل أي مهام حتى يستيقظ مجددًا:<syntaxhighlight lang="php">
php artisan queue:work --sleep=3
php artisan queue:work --sleep=3
ضبط Supervisor
</syntaxhighlight>
تثبيت Supervisor
==ضبط Supervisor==
Supervisor مراقب معالجات لنظام لينكس وسيعيد إطلاق المعالجات آليًا في حال فشلها. لتثبيت Supervisor، استعمل الأمر التالي:
===تثبيت Supervisor===
sudo apt-get install supervisor
Supervisor مراقب معالجات لنظام لينكس وسيعيد إطلاق المعالجات آليًا في حال فشلها. لتثبيت Supervisor، استعمل الأمر التالي:<syntaxhighlight lang="php">
ملاحظة: إذا كان ضبط supervisor بمفردك يبدو صعبا، فكر في استعمال Laravel forge الذي يثبت ويضبط supervisor تلقائيًا لتطبيقات Laravel.
sudo apt-get install supervisor  
ضبط Supervisor
</syntaxhighlight>ملاحظة: إذا كان ضبط supervisor بمفردك يبدو صعبا، فكر في استعمال Laravel forge الذي يثبت ويضبط supervisor تلقائيًا لتطبيقات Laravel.
توجد ملفات ضبط supervisor عادة في المجلد etc/supervisor/conf.d/. في هذا المجلد يمكنك أن تُنشِئ أي عدد من ملفات الضبط لإخبار supervisor كيف يراقب معالجاتك. مثلًا، لننشِئ الملف  laravel-worker.conf الذي يُطلق و يراقب معالجات queue:work:
===ضبط Supervisor===
توجد ملفات ضبط supervisor عادة في المجلد <code>etc/supervisor/conf.d/</code>. في هذا المجلد يمكنك أن تُنشِئ أي عدد من ملفات الضبط لإخبار supervisor كيف يراقب معالجاتك. مثلًا، لننشِئ الملف  <code>laravel-worker.conf</code> الذي يُطلق و يراقب معالجات <code>queue:work</code>:<syntaxhighlight lang="php">
[program:laravel-worker]
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
process_name=%(program_name)s_%(process_num)02d
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3
 
autostart=true
command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 autostart=true autorestart=true user=forge numprocs=8 redirect_stderr=true  
autorestart=true
 
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/home/forge/app.com/worker.log
stdout_logfile=/home/forge/app.com/worker.log
في هذا المثال، ستطلب التعليمة  numprocs من المراقب supervisor إطلاق 8 معالجات queue:work ومراقبتها كلها، وإعادة إطلاقها آليًا إن فشلت. طبعًا، يجب أن تغير queue:work sqs في التعليمة command للصلة التي تريد استخدامها.
 
تشغيل Supervisor
 
بعد صناعة ملف الضبط، يمكنك تحيين ضبط supervisor وتشغيله باستخدام الأوامر التالية:
</syntaxhighlight>في هذا المثال، ستطلب التعليمة  <code>numprocs</code> من المراقب supervisor إطلاق 8 معالجات <code>queue:work</code> ومراقبتها كلها، وإعادة إطلاقها آليًا إن فشلت. طبعًا، يجب أن تغير <code>queue:work</code> sqs في التعليمة <code>command</code> للصلة التي تريد استخدامها.
===تشغيل Supervisor===
بعد صناعة ملف الضبط، يمكنك تحيين ضبط supervisor وتشغيله باستخدام الأوامر التالية:<syntaxhighlight lang="php">
sudo supervisorctl reread
sudo supervisorctl reread


سطر 396: سطر 393:


sudo supervisorctl start laravel-worker:*
sudo supervisorctl start laravel-worker:*
للمزيد من المعلومات تفقد توثيق supervisor.
 
التعامل مع المهام الفاشلة
 
في بعض الأحيان، تفشل المهام. لا تقلق ، لا تسير الأمور دائما كالمتوقع. يتضمن Laravel طريقة سهلة لتحديد العدد الأقصى لمحاولة تنفيذ مهمة. بعد أن تتجاوز المهمة العدد الأقصى للمحاولات، تُضمَّن في الجدول failed_jobs في قاعدة البيانات. لصناعة ترحيل للجدول failed_jobs يمكن استعمال الأمر queue:failed_jobs:
</syntaxhighlight>للمزيد من المعلومات تفقد [http://supervisord.org/index.html توثيق supervisor].
==التعامل مع المهام الفاشلة==
في بعض الأحيان، تفشل المهام. لا تقلق ، لا تسير الأمور دائما كالمتوقع. يتضمن Laravel طريقة سهلة لتحديد العدد الأقصى لمحاولة تنفيذ مهمة. بعد أن تتجاوز المهمة العدد الأقصى للمحاولات، تُضمَّن في الجدول <code>failed_jobs</code> في قاعدة البيانات. لصناعة ترحيل للجدول <code>failed_jobs</code> يمكن استعمال الأمر <code>queue:failed_jobs</code>:<syntaxhighlight lang="php">
php artisan queue:failed-table
php artisan queue:failed-table
php artisan migrate
php artisan migrate
عند تشغيل عمال طوابير الانتظار، يجب أن تحدد العدد الأقصى لمحاولات تنفيذ المهام باستخدام الخيارtries-- مع الأمر queue:work. إذا لم تحدد قيمة للخيار tries--، فستعاد المحاولة دون توقف:
</syntaxhighlight>عند تشغيل عمال طوابير الانتظار، يجب أن تحدد العدد الأقصى لمحاولات تنفيذ المهام باستخدام الخيار <code>tries--</code> مع الأمر <code>queue:work</code>. إذا لم تحدد قيمة للخيار <code>tries--</code>، فستعاد المحاولة دون توقف:<syntaxhighlight lang="php">
php artisan queue:work redis --tries=3
php artisan queue:work redis --tries=3  
التنظيف بعد المهام الفاشلة
</syntaxhighlight>
يمكنك تعريف التابع failed مباشرة في صنف المهمة، مما يسمح لك بتنفيذ تنظيف خاص بالمهمة عند حدوث الفشل. هذا هو المكان الأمثل لإرسال تنبيه للمستخدمين أو عكس أي عمل قامت به المهمة. يُمرَّر الإستثناء الذي سبب فشل المهمة إلى التابع failed:
===التنظيف بعد المهام الفاشلة===
يمكنك تعريف التابع <code>failed</code> مباشرة في صنف المهمة، مما يسمح لك بتنفيذ تنظيف خاص بالمهمة عند حدوث الفشل. هذا هو المكان الأمثل لإرسال تنبيه للمستخدمين أو عكس أي عمل قامت به المهمة. يُمرَّر الإستثناء الذي سبب فشل المهمة إلى التابع <code>failed</code>:<syntaxhighlight lang="php">
<?php
<?php


namespace App\Jobs;
namespace App\Jobs;


use Exception;
use Exception; use App\Podcast; use App\AudioProcessor; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue;
use App\Podcast;
use App\AudioProcessor;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;


class ProcessPodcast implements ShouldQueue
class ProcessPodcast implements ShouldQueue {
{
    use InteractsWithQueue, Queueable, SerializesModels;


    protected $podcast;
  use InteractsWithQueue, Queueable, SerializesModels;
 
  protected $podcast;
    /**
  /**
    * Create a new job instance.
    * إنشاء نسخة مهمة
    *
    *
    * @param  Podcast  $podcast
    * @param  Podcast  $podcast
    * @return void
    * @return void
    */
    */
    public function __construct(Podcast $podcast)
  public function __construct(Podcast $podcast)
    {
  {
        $this->podcast = $podcast;
      $this->podcast = $podcast;
     }
  }
  /**
    * تنفيذ المهمة
    *
     * @param  AudioProcessor  $processor
    * @return void
    */
  public function handle(AudioProcessor $processor)
  {
      // Process uploaded podcast...
  }
  /**
    * فشلت المهمة في المواصلة
    *
    * @param  Exception  $exception
    * @return void
    */
  public function failed(Exception $exception)
  {
      // إرسال إشعار فشل للمستخدم
  }
}


    /**
    * Execute the job.
    *
    * @param  AudioProcessor  $processor
    * @return void
    */
    public function handle(AudioProcessor $processor)
    {
      // Process uploaded podcast...
    }


    /**
</syntaxhighlight>
    * The job failed to process.
===أحداث المهام الفاشلة===
    *
إذا أردت تسجيل حدث يُطلق عند فشل مهمة، يمكنك استخدام التابع <code>Queue:failing</code>. يمثل الحدث فرصة قيّمة لإعلام الفريق ببريد إلكتروني أو stride. مثلًا، يمكننا إرفاق نداء لهذا الحدث من <code>AppServiceProvider</code> المُضمَّنة في Laravel:<syntaxhighlight lang="php">
    * @param  Exception  $exception
    * @return void
    */
    public function failed(Exception $exception)
    {
      // Send user notification of failure, etc...
    }
}
 
أحداث المهام الفاشلة
إذا أردت تسجيل حدث يُطلق عند فشل مهمة، يمكنك استخدام التابع Queue:failing. يمثل الحدث فرصة قيّمة لإعلام الفريق ببريد إلكتروني أو stride. مثلًا، يمكننا إرفاق نداء لهذا الحدث من AppServiceProvider المُضمَّنة في Laravel:
<?php
<?php


namespace App\Providers;
namespace App\Providers;


use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Queue; use Illuminate\Queue\Events\JobFailed; use Illuminate\Support\ServiceProvider;
use Illuminate\Queue\Events\JobFailed;
use Illuminate\Support\ServiceProvider;


class AppServiceProvider extends ServiceProvider
class AppServiceProvider extends ServiceProvider {
{
    /**
    * Bootstrap any application services.
    *
    * @return void
    */
    public function boot()
    {
        Queue::failing(function (JobFailed $event) {
          // $event->connectionName
          // $event->job
          // $event->exception
        });
    }


     /**
  /**
    * Register the service provider.
    * تمهيد أي خدمات للتطبيق
    *
    *
    * @return void
     * @return void
    */
    */
    public function register()
  public function boot()
    {
  {
      //
      Queue::failing(function (JobFailed $event) {
    }
          // $event->connectionName
          // $event->job
          // $event->exception
      });
  }
  /**
    * تسجيل حاوي الخدمات
    *
    * @return void
    */
  public function register()
  {
      //
  }
}
}


إعادة تشغيل المهام الفاشلة
 
لإظهار كل المهام الفاشلة الموجودة في الجدول failed_jobs، استخدم الأمر queue:failed:
</syntaxhighlight>
php artisan queue:failed
=====إعادة تشغيل المهام الفاشلة=====
سيُظهر الأمر queue:failed معرَف المهمة، والصلة، وطابور الانتظار، ووقت الفشل. يمكن استعمال معرّف المهمة لإعادة تشغيلها. مثلا، لإعادة تشغيل المهمة الفاشلة ذات المعرَف 5، استعمل الأمر التالي:
لإظهار كل المهام الفاشلة الموجودة في الجدول <code>failed_jobs</code>، استخدم الأمر <code>queue:failed</code>:<syntaxhighlight lang="php">
php artisan queue:failed  
</syntaxhighlight>سيُظهر الأمر <code>queue:failed</code> معرَف المهمة، والصلة، وطابور الانتظار، ووقت الفشل. يمكن استعمال معرّف المهمة لإعادة تشغيلها. مثلا، لإعادة تشغيل المهمة الفاشلة ذات المعرَف 5، استعمل الأمر التالي:<syntaxhighlight lang="php">
php artisan queue:retry 5
php artisan queue:retry 5
لإعادة تشغيل كل المهام الفاشلة استعمل الأمر queue retry ومرّر all كمعرَف المهمة:
</syntaxhighlight>لإعادة تشغيل كل المهام الفاشلة استعمل الأمر <code>queue:retry</code> ومرّر all كمعرَف المهمة:<syntaxhighlight lang="php">
php artisan queue:retry all
php artisan queue:retry all
إذا أردت حذف مهمة فاشلة، استخدم الأمر queue:forget:
</syntaxhighlight>إذا أردت حذف مهمة فاشلة، استخدم الأمر <code>queue:forget</code>:<syntaxhighlight lang="php">
php artisan queue:forget 5
php artisan queue:forget 5  
لحذف كل المهام الفاشلة، يمكنك استخدام الأمر queue:flush:
</syntaxhighlight>لحذف كل المهام الفاشلة، يمكنك استخدام الأمر <code>queue:flush</code>:<syntaxhighlight lang="php">
php artisan queue:flush
php artisan queue:flush  
أحداث المهام
</syntaxhighlight>
باستخدام التابعين before و after من الواجهة الثابتة Queue، يمكن إنشاء نداء يٌنفّذ قبل أو بعد معالجة مهمة. تمثّل هذه النداءات فرصة جيدة للقيام بتسجيلات إضافية وزيادة الإحصاءات لواجهة التحكم. في العادة، يجب نداء هذه التوابع من مزود الخدمات. مثلًا، يمكنك استخدام AppServiceProvider المضمنة في Laravel:
==أحداث المهام==
باستخدام التابعين <code>before</code> و <code>after</code> من الواجهة الثابتة <code>Queue</code>، يمكن إنشاء نداء يٌنفّذ قبل أو بعد معالجة مهمة. تمثّل هذه النداءات فرصة جيدة للقيام بتسجيلات إضافية وزيادة الإحصاءات لواجهة التحكم. في العادة، يجب نداء هذه التوابع من مزود الخدمات. مثلًا، يمكنك استخدام <code>AppServiceProvider</code> المضمنة في Laravel:<syntaxhighlight lang="php">
<?php
<?php


namespace App\Providers;
namespace App\Providers;


use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Queue; use Illuminate\Support\ServiceProvider; use Illuminate\Queue\Events\JobProcessed; use Illuminate\Queue\Events\JobProcessing;
use Illuminate\Support\ServiceProvider;
 
use Illuminate\Queue\Events\JobProcessed;
class AppServiceProvider extends ServiceProvider {
use Illuminate\Queue\Events\JobProcessing;


class AppServiceProvider extends ServiceProvider
  /**
{
    * تمهيد أي خدمات للتطبيق
    /**
    *
    * Bootstrap any application services.
    * @return void
    *
    */
    * @return void
  public function boot()
    */
  {
    public function boot()
      Queue::before(function (JobProcessing $event) {
    {
          // $event->connectionName
        Queue::before(function (JobProcessing $event) {
          // $event->job
          // $event->connectionName
          // $event->job->payload()
          // $event->job
      });
          // $event->job->payload()
      Queue::after(function (JobProcessed $event) {
        });
          // $event->connectionName
          // $event->job
          // $event->job->payload()
      });
  }
  /**
    * تسجيل حاوي الخدمات
    *
    * @return void
    */
  public function register()
  {
      //
  }
}


        Queue::after(function (JobProcessed $event) {
          // $event->connectionName
          // $event->job
          // $event->job->payload()
        });
    }


    /**
</syntaxhighlight>باستخدام التابع <code>looping</code> من الواجهة الساكنة Queue، يمكنك تحديد نداءات قبل أن يحاول العامل إحضار المهمة من طابور الانتظار. مثلًا، يمكن تسجيل Closure لتنفيذ rollback على أي عملية نقل (transaction) غير مكتملة من مهام فاشلة:<syntaxhighlight lang="php">
    * Register the service provider.
    *
    * @return void
    */
    public function register()
    {
      //
    }
}
باستخدام التابع looping من الواجهة الثابتة Queue، يمكنك تحديد نداءات قبل أن يحاول العامل إحضار المهمة من طابور الانتظار. مثلًا، يمكن تسجيل Closure لتنفيذ rollback على أي عملية نقل (transaction) غير مكتملة من مهام فاشلة:
Queue::looping(function () {
Queue::looping(function () {
    while (DB::transactionLevel() > 0) {
 
        DB::rollBack();
  while (DB::transactionLevel() > 0) {
    }
      DB::rollBack();
  }
});
});
</syntaxhighlight>
== مصادر  ==
* <span> </span>[https://laravel.com/docs/5.6/queues صفحة Queues في توثيق Laravel الرّسمي.]
<noinclude>{{DISPLAYTITLE:طوابير الانتظار (Queues) في Laravel}}</noinclude>
[[تصنيف:Laravel|{{SUBPAGENAME}}]]
[[تصنيف:Laravel Digging deeper|{{SUBPAGENAME}}]]

المراجعة الحالية بتاريخ 14:11، 24 أكتوبر 2018

مقدمة

ملاحظة: يوفر Laravel الآن Horizon، لوحة تحكم وضبط للأنظمة المدعومة من طوابير انتظار Redis. تفقد توثيق Horizon لمزيد من المعلومات.

توفّر طوابير انتظار Laravel واجهة API موحدة بين مختلف طوابير انتظار البيئة الخلفية مثل Beanstalk أو Amazon SQS أو Redis أو قواعد البيانات العلائقية. تسمح ٌطوابير الانتظار بتأخير إنجاز المهام التي تتطلب الكثير من الوقت مثل إرسال بريد لوقت لاحق. تأخير هذه المهام يسرّع طلبات الويب في التطبيق بشكل كبير.

يوجد ملف ضبط طوابير الانتظار في config/queue.php. ستجد في هذا الملف ضبط صلة كل طابور انتظار مضمّنة في الإطار. والتي تتضمن قاعدة بيانات Beanstalkd أو Amazon SQS أو Redis ومشغل تزامني لتنفيذ المهام آنيًا (للاستعمال المحلي). يوجد أيضًا مشغل طوابير الانتظار null لتعطيل تنفيذ المهام المضافة للطابور.

مقارنة الصلة مع طابور الانتظار

قبل بدء العمل بطوابير انتظار Laravel، من المهم فهم الفرق بين طابور الانتظار "queue" والصلة "connection". يوجد في الملف config/queue.php خيار الضبط connections. يعرّف هذا الخيار صلة لخدمة خلفية مثل Amazon SQS أو Beanstalk أو Redis. لكن، يمكن أن تحتوي كل صلة على عدّة طوابير انتظار "queues" التي يمكن اعتبارها مكدس (stack) من المهام المنتظِرة.

لاحظ أنّ كل مثال ضبط صلة في ملف ضبط الطوابير يحتوي الخاصية queue. هذه هي للطابور الأولي التي تُرسَل له المهام عندما تُرسل للصلة المعيّنة. أي أنّك إن أرسلت مهمة دون تحديد أي طابور انتظار يجب استعمالها، فستُرسَل المهمّة للطابور المذكور في الخاصية queue في ضبط الصلة:

// إرسال مهمة دون ذكر الطابور
 Job::dispatch();

// إرسال المهمة لطابور محدد
 Job::dispatch()->onQueue('emails');

قد لا تحتاج بعض التطبيقات لإرسال مهام لطوابير متعدد أبدًا بل تفضّل وجود طابور واحد. لكن يكون تعدد طوابير الانتظار مفيدًا للتطبيقات التي تريد إعطاء أولوية أو تقسيم معالجة المهام إذ تسمح عمّال Laravel بتحديد أي طابور انتظار يجب معالجتها و بأي أولوية. مثلًا، إذا أرسلت مهام لطابور الانتظار high، يمكنك إطلاق عامل بأولوية معالجة مرتفعة:

php artisan queue:work --queue=high,default

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

Database

لاستخدام برنامج تشغيل طوابير الانتظار database، ستحتاج إلى جدول في قاعدة البيانات ليحمل المهام. لتوليد ترحيل يصنع الجدول، نفّذ الأمر queue:table. بعد إنشاء الترحيل يمكنك تنفيذه باستعمال الأمر migrate:

php artisan queue:table

php artisan migrate

Redis

لاستعمال برنامج تشغيل طوابير الانتظار Redis، يجب ضبط صلة قاعدة بيانات Redis في ملف الضبط config/database.php.

Redis Cluster

إذا كانت صلة Redis تستعمل تجميعات Redis Cluster، يجب أن يحتوي اسم الطابور على مفتاح hash tag. هذا مطلوب للتأكد من أن كل المفاتيح المتوفّرة موجودة في نفس المكان:

'redis' => [

   'driver' => 'redis',
   'connection' => 'default',
   'queue' => '{default}',
   'retry_after' => 90,
],
الإيقاف

عند استعمال طوابير انتظار Redis، يمكن استعمال خيار الضبط block_for لتحديد المدة التي يجب أن ينتظرها المشغل لتصبح المهمة متوفرة قبل أن يواصل بقية العملة ويعيد سحب قاعدة بيانات Redis.

قد يكون تعديل هذه القيمة حسب حجم طابور الانتظار أكثر فاعلية من السحب المتواصل لمهام جديدة من قاعدة بيانات Redis. يمكنك مثلا إعطاؤها القيمة 5 لإيقاف المشغل 5 ثوان في حين ينتظر أن تصبح المهمة متوفرة:

'redis' => [

   'driver' => 'redis',
   'connection' => 'default',
   'queue' => 'default',
   'retry_after' => 90,
   'block_for' => 5,
],

تنبيه: Blocking pop هي خاصية تجريبية. يوجد إمكانية بسيطة بأن تضيع مهمة في خادم Redis أو أن يتوقف عامل عن العمل وقت استرجاع المهمة.

متطلبات برامج تشغيل أخرى

تحتاج التبعيات التالية لبرامج التشغيل المذكورة:

  • Amazon SQS: aws/aws-sdk-php ~3.0
  • Beanstalkd: pda/pheanstalk ~3.0
  • Redis: predis/predis ~1.0

إنشاء المهام

توليد أصناف المهام

في العادة، توجد كل المهام التي يمكن إضافتها لطوابير الانتظار في المجلد app/Jobs. إذا لم يكن المجلد موجودًا فسينشَأ عند تنفيذ الأمر make:job. يمكنك إحداث مهمّة جديدة باستخدام سطر الأوامر:

php artisan make:job ProcessPodcast

سيُنفّذ الصنفُ المُنشَأ الواجهةَ Illuminate\Contracts\Queue\ShouldQueue، ويُعلم Laravel أنّ المهمة يجب أن تضاف لقامة انتظار وتُنفّذ بطريقة غير متزامنة.

هيكلة الصنف

أصناف المهام بسيطة، تحتوي في العادة فقط على التابع handle الذي ينادَى عند معالجة المهمّة من قبل طابور الانتظار. للبدء، لنلق نظرة على مثال صنف مهمة. في هذا المثال، سنتظاهر بإدارة خدمة نشر تدوين صوتي و نحتاج لمعالجة الملفات المرفوعة قبل نشرها:

<?php

namespace App\Jobs;

use App\Podcast; use App\AudioProcessor; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable;

class ProcessPodcast implements ShouldQueue {

   use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
   protected $podcast;
   /**
    * إنشاء المهمة
    *
    * @param  Podcast  $podcast
    * @return void
    */
   public function __construct(Podcast $podcast)
   {
       $this->podcast = $podcast;
   }
   /**
    * تنفيذ المهمة.
    *
    * @param  AudioProcessor  $processor
    * @return void
    */
   public function handle(AudioProcessor $processor)
   {
      // معالجة الملفات المرفوعة.
   }
}

في هذا المثال، لاحظ أنه يمكننا تمرير نموذج Eloquent مباشرة للتابع الباني للمهمة. بسبب الخاصية SerializeModels التي تستعملها المهمة، تكون نماذج Eloquent متسلسلة أو غير متسلسلة بلباقة عند معالجة المهمّة. إذا كانت المهمّة المنتظِرة تقبل نموذجًا في التابع الباني، ستتم سلسلة معرّف النموذج فقط في طابور الانتظار. عند التعامل الفعلي مع المهمة، يسترجع النظام تلقائيًا كامل النموذج من قاعدة البيانات. كل هذا واضح للتطبيق ويوقف المشاكل التي يمكن أن تحصل من سلسلة كامل النموذج.

يُنادى التابع handle عند معالجة المهمة من قبل طابور الانتظار. لاحظ أنّه يمكنك تقريب أنواع التبعيات في التابع handle. يضيف حاوي خدمات Laravel تلقائيا هذه التبعيات.

تنبيه: يجب أن تمرّر البيانات الثنائية (binary) مثل الصور الخام عبر الدالة ase64_encode قبل تمريرها لمهمة منتظِرة وإلّا قد لا تتم سَلسلتها لشيفرة JSON بطريقة صحيحة عند إضافتها لطابور الانتظار.

إرسال المهام

بعد كتابة صنف المهمة، يمكنك ارسالها باستعمال التابع dispatch على المهمة نفسها. المعاملات الممررة للتابع dispatch ستمرّر للتابع الباني للمهمة:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast; use Illuminate\Http\Request; use App\Http\Controllers\Controller;

class PodcastController extends Controller {

   /**
    * حفظ تدوينة جديدة
    *
    * @param  Request  $request
    * @return Response
    */
   public function store(Request $request)
   {
      // Create podcast...
       ProcessPodcast::dispatch($podcast);
   }
}

الإرسال المتأخر

إذا أردت تأخير تنفيذ مهمّة في طابور الانتظار، يمكنك استعمال التابع delay عند إرسال المهمّة. مثلًا، لنحدد أن المهمة يجب ألّا تكون متوافرة إلا بعد 10 دقائق بعد إرسالها:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast; use Illuminate\Http\Request; use App\Http\Controllers\Controller;

class PodcastController extends Controller {

   /**
    * حفظ تدوينة جديدة.
    *
    * @param  Request  $request
    * @return Response
    */
   public function store(Request $request)
   {
      // Create podcast...
       ProcessPodcast::dispatch($podcast)
               ->delay(now()->addMinutes(10));
   }
}

تنبيه: خدمة Amazon SQS لديها حد تأخير أقصى يساوي 15 دقيقة.

تسلسل المهام

يسمح تسلسل المهام بتحديد مجموعة من المهام التي يجب تنفيذها بالتسلسل. إذا فشل تنفيذ أحد المهام، فلن تُنفَّذ البقية. لتنفيذ سلسلة مهام، يمكن استخدام التابع withChain على أي مهمة قابلة للإرسال:

ProcessPodcast::withChain([

   new OptimizePodcast,
   new ReleasePodcast
])->dispatch();

اتصال السلسلة وطابور الانتظار

إذا أردت تعريف اتصال وطابور انتظار أولي لسلسلة المهام، يمكن استعمال التابعين allOnConnection و allOnQueue. يحدد هذان التابعان الاتصال و طابور الانتظار الواجب استعمالها في حالة عدم تحديد الاتصال و طابور الانتظار فعليا:

ProcessPodcast::withChain([

   new OptimizePodcast,
   new ReleasePodcast
])->dispatch()->allOnConnection('redis')->allOnQueue('podcasts');

تخصيص الصلة و طابور الانتظار

الإرسال لطابور انتظار معين

بإرسال المهام لطوابير مختلفة، يمكنك تصنيف المهام وحتى إعطاء أولوية لعدد العملة المرفقة بكل طابور انتظار. تذكر أنّ هذا لا يُرسل المهام لصلات مختلفة كما عُرِّفت في ملف الضبط، بل فقط لطوابير معيّنة في صلة واحدة. لتخصيص صلة مغيرة، استعمل التابع onQueue عند إرسال المهمّة:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast; use Illuminate\Http\Request; use App\Http\Controllers\Controller;

class PodcastController extends Controller {

   /**
    * حفظ تدوينة جديدة
    *
    * @param  Request  $request
    * @return Response
    */
   public function store(Request $request)
   {
      // Create podcast...
       ProcessPodcast::dispatch($podcast)->onConnection('sqs');
   }
}

الإرسال لاتصال معيّن

في حال كنت تتعامل مع اتصالات طوابير انتظا مختلفة، يمكنك تحديد الاتصال لإرسال مهمّة ما وذلك باستخدام التابع onConnection:

<?php

namespace App\Http\Controllers;

use App\Jobs\ProcessPodcast;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class PodcastController extends Controller
{
    /**
     * حفظ تدوينة جديدة
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        // إنشاء تدوينة

        ProcessPodcast::dispatch($podcast)->onConnection('sqs');
    }
}

بالطبع يمكنك سَلسلة onConnection و onQueue لتخصيص الصلة و الطابور:

ProcessPodcast::dispatch($podcast)

             ->onConnection('sqs')
             ->onQueue('processing');

تحديد العدد الأقصى للمحاولات ومدة الانتظار

الحد الأقصى للمحاولات

إحدى الطرائق لتحديد العدد الأقصى للمحاولات تنفيذ مهمّة هي استعمال الخيار tries-- مع أمر artisan:

php artisan queue:work --tries=3

لكن يمكنك اتخاذ طريقة عمل أكثر حُبيبية بتعريف العدد الأقصى للمحاولات في صنف المهمة نفسه. إذا كان العدد الأقصى محددًا في صنف المهمة، ستأخذ أولية على القيمة المحددة في سطر الأوامر:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue {

   /**
    * العدد الأقصى للمحاولات.
    *
    * @var int
    */
   public $tries = 5;
}

المحاولات على أساس الوقت

كبديل لتحديد العدد الأقصى لمحاولات تنفيذ مهمة قبل إعلان فاشلها، يمكن تحديد الوقت الذي تفشل المهمة إذا تجاوزته. يسمح هذا للمهمة بمحاولة التنفيذ أي عدد من المرات في الوقت المحدد. لتعريف المدة الانتظار، أضف التابع retryUntil لصنف المهمة:

/**

* تحديد زمن الانتظار.
*
* @return \DateTime
*/
public function retryUntil() {

   return now()->addSeconds(5);
}

ملاحظة: يمكنك أيضًا تعريف retryUntil في مستمع أحداث الإضافة لطابور الانتظار.

نفاذ الوقت Timeout

تنبيه: الخاصية timeout تعمل بطريقة أمثل مع PHP 7.1+‎ والإضافة pcntl.

يمكن أيضًا تحديد عدد ثواني الانتظار باستخدام الخيار timeout مع أمر artisan:

php artisan queue:work --timeout=30

لكن، يمكن أيضًا تحديد عدد ثواني الانتظار في صنف المهمة نفسه. إذا حُدد timeout في صنف المهمة تكون له الأولوية على القيمة المحددة في سطر الأوامر:

<?php

namespace App\Jobs;

class ProcessPodcast implements ShouldQueue {

   /**
    *عدد ثواني العمل قبل إنهاء المهمة.
    *
    * @var int
    */
   public $timeout = 120;
}

تحديد معدل التنفيذ

تنبيه: تتطلب هذه الخاصية أن يتعامل التطبيق مع خادم Redis.

إذا كان التطبيق يتعامل مع خادم Redis، يمكنك ترتيب المهام المنتظِرة حسب الوقت أو التنافسية. تساعد هذه الخاصية خاصة عندما تتعامل المهام مع واجهات API هي أيضًا محدودة. مثلًا، باستخدام التابع throttle، يمكنك تحديد أن لا يتجاوز تنفيذ نوع معين من المهام 10 مرات كل 60 ثانية. إذا كان الحصول على قفلٍ غيرُ ممكنٍ، يمكنك تحرير المهمة لتعاد محاولة تنفيذها لاحقًا:

Redis::throttle('key')->allow(10)->every(60)->then(function () {

  // Job logic...
}, function () {

  // لا يمكن الحصول على قفل..
   return $this->release(10);
});

ملاحظة: في المثال السابق، يمكن أن تكون قيمة key أي سلسلة حروف تعرف بصفة فريدة نوع المهمة تريد تحديد معدّل تنفيذها. مثلًا، قد تريد صناعة المفتاح باستخدام اسم صنف المهمة ومعرّف النموذج الذي تعمل عليه. بدل ذلك، يمكنك تحديد العدد الأقصى للعمّال المتوازين على نفس المهمة. تكون هذه الخاصية مفيدة عند العمل مع موارد لا تقبل أكثر من مهمة واحدة في الوقت. مثلاً، استخدم التابع funnel لتحديد نوع المهام التي يجب تنفيذها من قبل عامل واحد:

Redis::funnel('key')->limit(1)->then(function () {

  // Job logic...
}, function () {

  // Could not obtain lock...
   return $this->release(10);
});

ملاحظة: عند استعمال تحديد التنفيذ، قد يكون من الصعب تحديد عدد المحاولات اللازمة لإنجاح المهمة بدقة. لذلك من المفيد دمج تحديد التنفيذ مع المحاولات المقيدة بوقت.

التعامل مع الأخطاء

إذا أُطلق استثناء حين معالجة المهمّة، تُطلق المهمة تلقائيًا لطابور الانتظار لتتم محاولة إعادة تنفيذها لاحقا. تبقى المهمة في حالة إطلاق حتى تصل للحد الأقصة المسموح من المحاولات. يُحدَّد العدد الأقصى للمحولات باستعمال الخيار tries-- مع الأمر queue:work. يمكن أيضًا تحديد الحد الأقصى للمحاولات في صنف المهمة. المزيد من المعلومات عن تشغيل عمّال الطوابير فيما يلي.

تشغيل عمّال الطابور

يتضمّن Laravel عامل طوابير انتظار يعالج المهم الجديدة عند دفعها للطابور. يمكن تشغيل عامل بتنفيذ الأمر queue:work. لاحظ أنّه عند بدء الأمر، سيواصل العمل إلى أن يتم إيقافه يدويًا أو إغلاق الطرفية:

php artisan queue:work

ملاحظة: لإبقاء معالج الأمر queue:work يعمل بطريقة دائمة في الخلفية، يجب عليك استخدام مراقب معالجات مثل supervisor للتأكد من أن المعالج لم يتوقف فجأة. تذكر أن العمّال معالجاتٌ تعيش طويلًا وتسجّل حالة التطبيق في الذاكرة و بالتالي لن تلاحظ أي تغيير في التطبيق بعد إطلاقها، لذا تأكد من إعادة إطلاقها بعد نشر التطبيق.

معالجة مهمة واحدة

يُستعمل الخيار once-- لإخبار العامل بمعالجة مهمة واحدة من طابور الانتظار:

php artisan queue:work --once

تخصيص اتصال وطابور انتظار

يمكنك تحديد أي اتصال على العامل استخدامه. يجب أن يتوافق اسم الاتصال الممرّر للأمر work مع إحدى الصّلات المعرفة في ملف الضبط config/queue.php:

php artisan queue:work redis

يمكنك تخصيص العامل أكثر عبر معالجة طوابير معيّنة فقط من الاتصال. مثلًا، إذا كانت كل رسائل البريد الإلكتروني تُعالَج في طابور انتظار واحد emails من الصلة redis، يمكنك إطلاق عامل يعالج فقط ذلك الطابور باستعمال الأمر التالي:

php artisan queue:work redis --queue=emails

مراعاة الموارد

عاملوا طوابير الانتظار في الخلفية لا تُعيد إقلاع الإطار قبل معالجة كل مهمة، لذا يجب عليك تحرير أي موارد ثقيلة بعد انتهاء كل مهمة. لو كنت مثلا تعمل على معالجة الصور باستعمال المكتبة GD، يجب عليك تحرير الذاكرة باستخدام الدالة imagedestroy عند الإنتهاء.

أولويات طوابير الانتظار

قد تريد في بعض الأحيان إعطاء أولوية لمعالجة طوابير الانتظار. مثلًا، في ملف الضبط config/queue.php يمكنك أن أن تضبط الطابور الأولي للصلة redis بالقيمة low لكن فد تريد في بعض الأحيان إضافة مهمة لطابور أعلى أولوية high كالآتي:

dispatch((new Job)->onQueue('high'));

لإطلاق عامل يتثبت من أن كل المهام ذات أولوية مرتفعة high قد عولجت قبل المواصلة لبقية المهام low، مرّر لائحة من أسماء طوابير الانتظار مفرّقف بفاصلة ',' إلى الأمر work:

php artisan queue:work --queue=high,low

عملة طوابير الانتظار والنشر على الخادم الإنتاجي

حيث أن العمّال معالجات تعيش طويلا، لن تلاحظ تغييرات في الشيفرة إن لم تتم إعادة إطلاقها. لذا، الطريقة الأسهل نشر تطبيق يستعمل عمّال الطوابير هي إعادة إطلاق العمّال في عملية النشر. يمكنك إعادة نشر العمال بسهولة باستخدام الأمر queue:restart:

php artisan queue:restart

سيطلب هذا الأمر من العمال جميعًا الانتهاء بعد إنهاء المهمة الحالية حتى لا تضيع أي مهمة موجودة. حيث سينتهي العمال الموجودون بعد الأمر queue:restart، يجب أن تملك مراقب معالجات مثل Supervisor ليعيد إطلاقهم آليًا.

ملاحظة: تستعمل طوابير الانتظار التخزين المؤقت cache لحفظ إشارة إعادة الإطلاق، لذا يجب عليك التأكد من ضبط مشغل تخزين مؤقت قبل استخدام هذه الخاصية.

صلاحية المهام ونفاذ الوقت

إنتهاء صلاحية المهام

في ملف config/queue.php، تعرّف كل صلة الخيار retry_after. يحدّد هذا الخيار عدد الثواني الذي يجب أن تنتظرها الصلة قبل محاولة إعادة تنفيذ مهمة تتم معالجتها. مثلًا، إن كانت قيمة retry_after تساوي 90، تُعاد المهمة للطابور إذا تمت معالجتها لمدة 90 ثانية دون حذفها. في العادة، يجب ضبط قيمة retry_after للمدة المعقولة التي تستغرقها المهمة لإكمال المعالجة.

تنبيه: الصلة الوحيدة التي لا تتضمن retry_after هي Amazon SQS. يعيد SQS محاولة التنفيذ حسب الوقت المبدئي للرؤية الذي يحدد في سطر أوامر AWS.

وقت نفاذ العامل

يملك الأمر queue:work الخيار timeout--. يحدد هذا الخيار المدة التي ينتظرها المعالج الرئيسي لطوابير الانتظار في Laravel قبل أن ينهي عامل طابور انتظار فرعية بصدد معالجة مهمة. في بعض الأحيان، يصبح عامل إحدى الطوابير الفرعية متجمّدا "frozen" لعدة أسباب، كنداء HTTP خارجي غير متجاوب. يحذف الخيار timeout-- المعالجات المتجمدة التي تتجاوز المدة المحددة في الخيار:

php artisan queue:work --timeout=60

خيار الضبط retry_after وخيار الأمر timeout-- مختلفان، لكن يعملان معًا للتأكد من أن المهمة لا تضيع ولا تعالج بطريقة ناجحة إلا مرّة واحدة.

تنبيه: قيمة timeout-- يجب أن تكون دومًا أقصر بعدّة ثواني على الأقل من قيمة retry_after. سيضمن هذا أن العامل الذي يعالج مهمة معينة ينتهي قبل إعادة محاولة المهمة. إذا كانت مدة timeout-- أطول من retry_after قد تتم معالجة المهمة مرتين.

مدة نوم العامل

عندما تتوفر مهام في طابور الانتظار يواصل العامل العمل دون تأخير بينها. لكن، يحدد الخيار sleep مدة نوم العامل (بالثواني) في حالة عدم وجود مهام متوفرة. عند نومه، لن يعالج العامل أي مهام حتى يستيقظ مجددًا:

php artisan queue:work --sleep=3

ضبط Supervisor

تثبيت Supervisor

Supervisor مراقب معالجات لنظام لينكس وسيعيد إطلاق المعالجات آليًا في حال فشلها. لتثبيت Supervisor، استعمل الأمر التالي:

sudo apt-get install supervisor

ملاحظة: إذا كان ضبط supervisor بمفردك يبدو صعبا، فكر في استعمال Laravel forge الذي يثبت ويضبط supervisor تلقائيًا لتطبيقات Laravel.

ضبط Supervisor

توجد ملفات ضبط supervisor عادة في المجلد etc/supervisor/conf.d/. في هذا المجلد يمكنك أن تُنشِئ أي عدد من ملفات الضبط لإخبار supervisor كيف يراقب معالجاتك. مثلًا، لننشِئ الملف laravel-worker.conf الذي يُطلق و يراقب معالجات queue:work:

[program:laravel-worker]

process_name=%(program_name)s_%(process_num)02d

command=php /home/forge/app.com/artisan queue:work sqs --sleep=3 --tries=3 autostart=true autorestart=true user=forge numprocs=8 redirect_stderr=true 

stdout_logfile=/home/forge/app.com/worker.log

في هذا المثال، ستطلب التعليمة numprocs من المراقب supervisor إطلاق 8 معالجات queue:work ومراقبتها كلها، وإعادة إطلاقها آليًا إن فشلت. طبعًا، يجب أن تغير queue:work sqs في التعليمة command للصلة التي تريد استخدامها.

تشغيل Supervisor

بعد صناعة ملف الضبط، يمكنك تحيين ضبط supervisor وتشغيله باستخدام الأوامر التالية:

sudo supervisorctl reread

sudo supervisorctl update

sudo supervisorctl start laravel-worker:*

للمزيد من المعلومات تفقد توثيق supervisor.

التعامل مع المهام الفاشلة

في بعض الأحيان، تفشل المهام. لا تقلق ، لا تسير الأمور دائما كالمتوقع. يتضمن Laravel طريقة سهلة لتحديد العدد الأقصى لمحاولة تنفيذ مهمة. بعد أن تتجاوز المهمة العدد الأقصى للمحاولات، تُضمَّن في الجدول failed_jobs في قاعدة البيانات. لصناعة ترحيل للجدول failed_jobs يمكن استعمال الأمر queue:failed_jobs:

php artisan queue:failed-table
php artisan migrate

عند تشغيل عمال طوابير الانتظار، يجب أن تحدد العدد الأقصى لمحاولات تنفيذ المهام باستخدام الخيار tries-- مع الأمر queue:work. إذا لم تحدد قيمة للخيار tries--، فستعاد المحاولة دون توقف:

php artisan queue:work redis --tries=3

التنظيف بعد المهام الفاشلة

يمكنك تعريف التابع failed مباشرة في صنف المهمة، مما يسمح لك بتنفيذ تنظيف خاص بالمهمة عند حدوث الفشل. هذا هو المكان الأمثل لإرسال تنبيه للمستخدمين أو عكس أي عمل قامت به المهمة. يُمرَّر الإستثناء الذي سبب فشل المهمة إلى التابع failed:

<?php

namespace App\Jobs;

use Exception; use App\Podcast; use App\AudioProcessor; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue;

class ProcessPodcast implements ShouldQueue {

   use InteractsWithQueue, Queueable, SerializesModels;
   protected $podcast;
   /**
    * إنشاء نسخة مهمة
    *
    * @param  Podcast  $podcast
    * @return void
    */
   public function __construct(Podcast $podcast)
   {
       $this->podcast = $podcast;
   }
   /**
    * تنفيذ المهمة
    *
    * @param  AudioProcessor  $processor
    * @return void
    */
   public function handle(AudioProcessor $processor)
   {
      // Process uploaded podcast...
   }
   /**
    * فشلت المهمة في المواصلة
    *
    * @param  Exception  $exception
    * @return void
    */
   public function failed(Exception $exception)
   {
      // إرسال إشعار فشل للمستخدم
   }
}

أحداث المهام الفاشلة

إذا أردت تسجيل حدث يُطلق عند فشل مهمة، يمكنك استخدام التابع Queue:failing. يمثل الحدث فرصة قيّمة لإعلام الفريق ببريد إلكتروني أو stride. مثلًا، يمكننا إرفاق نداء لهذا الحدث من AppServiceProvider المُضمَّنة في Laravel:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Queue; use Illuminate\Queue\Events\JobFailed; use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider {

   /**
    * تمهيد أي خدمات للتطبيق
    *
    * @return void
    */
   public function boot()
   {
       Queue::failing(function (JobFailed $event) {
          // $event->connectionName
          // $event->job
          // $event->exception
       });
   }
   /**
    * تسجيل حاوي الخدمات
    *
    * @return void
    */
   public function register()
   {
      //
   }
}
إعادة تشغيل المهام الفاشلة

لإظهار كل المهام الفاشلة الموجودة في الجدول failed_jobs، استخدم الأمر queue:failed:

php artisan queue:failed

سيُظهر الأمر queue:failed معرَف المهمة، والصلة، وطابور الانتظار، ووقت الفشل. يمكن استعمال معرّف المهمة لإعادة تشغيلها. مثلا، لإعادة تشغيل المهمة الفاشلة ذات المعرَف 5، استعمل الأمر التالي:

php artisan queue:retry 5

لإعادة تشغيل كل المهام الفاشلة استعمل الأمر queue:retry ومرّر all كمعرَف المهمة:

php artisan queue:retry all

إذا أردت حذف مهمة فاشلة، استخدم الأمر queue:forget:

php artisan queue:forget 5

لحذف كل المهام الفاشلة، يمكنك استخدام الأمر queue:flush:

php artisan queue:flush

أحداث المهام

باستخدام التابعين before و after من الواجهة الثابتة Queue، يمكن إنشاء نداء يٌنفّذ قبل أو بعد معالجة مهمة. تمثّل هذه النداءات فرصة جيدة للقيام بتسجيلات إضافية وزيادة الإحصاءات لواجهة التحكم. في العادة، يجب نداء هذه التوابع من مزود الخدمات. مثلًا، يمكنك استخدام AppServiceProvider المضمنة في Laravel:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Queue; use Illuminate\Support\ServiceProvider; use Illuminate\Queue\Events\JobProcessed; use Illuminate\Queue\Events\JobProcessing;

class AppServiceProvider extends ServiceProvider {

   /**
    * تمهيد أي خدمات للتطبيق
    *
    * @return void
    */
   public function boot()
   {
       Queue::before(function (JobProcessing $event) {
          // $event->connectionName
          // $event->job
          // $event->job->payload()
       });
       Queue::after(function (JobProcessed $event) {
          // $event->connectionName
          // $event->job
          // $event->job->payload()
       });
   }
   /**
    * تسجيل حاوي الخدمات
    *
    * @return void
    */
   public function register()
   {
      //
   }
}

باستخدام التابع looping من الواجهة الساكنة Queue، يمكنك تحديد نداءات قبل أن يحاول العامل إحضار المهمة من طابور الانتظار. مثلًا، يمكن تسجيل Closure لتنفيذ rollback على أي عملية نقل (transaction) غير مكتملة من مهام فاشلة:

Queue::looping(function () {

   while (DB::transactionLevel() > 0) {
       DB::rollBack();
   }
});

مصادر