مراقبة طوابير Laravel بـHorizon: المقاييس التي تكشف الاختناق
Horizon يعطيك ثلاثة أرقام تحسم كل شيء: الإنتاجية (jobs/دقيقة)، زمن التنفيذ، وزمن الانتظار. إذا ارتفع الانتظار وبقي زمن التنفيذ ثابتاً فالحل عمّال أكثر، وإذا ارتفع زمن التنفيذ نفسه فالمشكلة في كودك لا في عدد العمّال.
Laravel Horizon لوحة مراقبة لطوابير Redis تعطيك ثلاثة أرقام تحسم قرارك: الإنتاجية (كم مهمة تُنجز في الدقيقة)، زمن التنفيذ (كم يستغرق تشغيل المهمة الواحدة)، وزمن الانتظار (كم تبقى المهمة في الطابور قبل أن يلتقطها عامل). القراءة الصحيحة لهذه الأرقام الثلاثة تخبرك مباشرة أين الاختناق. إذا ارتفع زمن الانتظار بينما بقي زمن التنفيذ ثابتاً، فطوابيرك تصل أسرع مما يستطيع عمّالك ابتلاعه، والحل زيادة العمّال أو رفع سقفهم في الإعداد. أما إذا ارتفع زمن التنفيذ نفسه، فكل مهمة صارت أثقل، والمشكلة في كودك أو في استعلام قاعدة بيانات بطيء داخل المهمة، وزيادة العمّال هنا تحرق موارد سيرفرك بلا فائدة. لتفعيل Horizon تُثبّته بـcomposer require laravel/horizon ثم php artisan horizon:install، وتشغّله بأمر php artisan horizon الذي يقرأ إعداداتك من ملف config/horizon.php ويدير العمّال نيابة عنك بدل تشغيل queue:work يدوياً. تفتح اللوحة على مسار /horizon فترى القوائم، والمهام الفاشلة، والمقاييس الحيّة لحظة بلحظة. هذا المقال يشرح كيف تقرأ كل رقم، ومتى تلجأ لاستراتيجية balance=auto مقابل simple، وكم عاملاً يحتمل سيرفر متوسط بالأرقام، مع مثال supervisor واحد مقابل عدة قوائم بأولويات مختلفة.
ماذا يقيس Horizon فعلياً
الإنتاجية (throughput) هي عدد المهام المنجزة في وحدة زمن، وهي مؤشرك الأول على صحة النظام. إذا كان معدل وصول المهام 200 في الدقيقة وإنتاجيتك 120 فقط، فأنت تتراكم بمعدل 80 مهمة كل دقيقة، والطابور ينمو حتى ينفجر زمن الانتظار. زمن التنفيذ (runtime) يقيس المدة من لحظة التقاط العامل للمهمة حتى انتهائها، وهو انعكاس مباشر لثقل الكود: إرسال بريد قد يأخذ 300 ميلي ثانية، بينما توليد تقرير PDF ضخم قد يأخذ 8 ثوانٍ. زمن الانتظار (wait time) هو الفجوة بين دخول المهمة الطابور والتقاطها، وهو الرقم الذي يشعر به المستخدم فعلاً حين ينتظر وصول رسالة تأكيد أو فاتورة. Horizon يعرض هذه الثلاثة لكل قائمة على حدة، فترى بوضوح أن قائمة emails صحّية بينما قائمة reports مختنقة، وتتصرف على أساس البيانات لا التخمين.
قراءة الأرقام مع بعضها
القاعدة العملية بسيطة: راقب زمن الانتظار وزمن التنفيذ جنباً إلى جنب. ارتفاع الانتظار مع ثبات التنفيذ يعني نقص طاقة استيعابية، فأضف عمّالاً. ارتفاع التنفيذ نفسه يعني مهمة صارت أبطأ، فادخل الكود وابحث عن استعلام N+1 أو نداء API خارجي بلا مهلة زمنية. أما ثبات الاثنين مع تراجع الإنتاجية فيعني غالباً أن عمّالك يُعاد تشغيلهم كثيراً أو يموتون بلا إشراف، وهنا تفحص إعداد supervisor على السيرفر. اضبط تنبيهاً على عتبة زمن انتظار محددة، فمثلاً إذا تجاوز الانتظار في قائمة الفواتير دقيقتين، يصلك إشعار قبل أن يشتكي العميل.
balance=auto مقابل simple مقابل false
Horizon يدير توزيع العمّال على القوائم بثلاث استراتيجيات. simple يوزّع العمّال بالتساوي على القوائم بلا مراعاة للحمل، فإذا كان عندك ثلاث قوائم وعشرة عمّال، تحصل كل قائمة على نصيب ثابت تقريباً بغض النظر عن ازدحامها. auto هو الخيار الذكي: يراقب زمن الانتظار في كل قائمة وينقل العمّال تلقائياً نحو القائمة الأكثر ازدحاماً، فإذا امتلأت قائمة التقارير فجأة، يسحب Horizon عمّالاً من قائمة هادئة ويرميهم على التقارير حتى تهدأ. false يعطّل الموازنة ويثبّت عدد عمّال كل قائمة كما حددته أنت، وهو مناسب حين تريد ضماناً صارماً بأن قائمة حسّاسة لا تُجوّع أبداً. للأغلب الساحق من التطبيقات، auto هو الصحيح لأنه يتكيّف مع تقلّب الحمل بلا تدخّل يدوي.
| الاستراتيجية | كيف توزّع العمّال | متى تختارها |
|---|---|---|
| simple | توزيع ثابت متساوٍ على القوائم | حمل مستقر ومتشابه بين القوائم |
| auto | تنقل العمّال ديناميكياً نحو الازدحام | الخيار الافتراضي لأغلب التطبيقات |
| false | عدد ثابت يدوي لكل قائمة | ضمان صارم لقائمة حسّاسة |
مع auto تضبط أيضاً minProcesses وmaxProcesses، فتضمن حداً أدنى من العمّال جاهزين دائماً وسقفاً لا يتجاوزه حتى لا يلتهم Horizon كل رام السيرفر تحت ضغط مفاجئ.
كم عاملاً يحتمل سيرفرك بالأرقام
كل عامل Horizon عملية PHP مستقلة تستهلك رام ثابتة، وغالباً بين 40 و80 ميغابايت لتطبيق Laravel نموذجي حسب حجم الكود والحزم المحمّلة. على باقة خادم سحابي نمو بمواصفات 2 vCPU و4GB رام، بعد أن تخصم رام نظام التشغيل وخدمة PHP-FPM وRedis، يتبقى لك نحو 2.5GB عملية للعمّال، أي مجال مريح لنحو 25 إلى 35 عاملاً متزامناً إذا كانت مهامك خفيفة (بريد، إشعارات). لكن العدد ليس الحكاية كاملة: عاملان اثنان فقط على مهام تولّد PDF ثقيلة قد يشبعان الـ2 vCPU تماماً، لأن القيد هنا المعالج لا الذاكرة. لهذا تُقاس السعة بتجربة فعلية: ارفع العمّال تدريجياً وراقب استهلاك vCPU في لوحة السيرفر، فإذا ثبت عند 80% ولم تتحسّن الإنتاجية، فقد بلغت السقف وتحتاج ترقية الباقة أو إضافة vCPU بدل حشر عمّال أكثر. إضافة vCPU واحد في كلاود بـ500 ريال سنوياً، وإضافة 2GB رام بـ600 ريال سنوياً، والترقية فورية بلا توقف الخدمة.
supervisor واحد مقابل عدة قوائم بأولويات
الخطأ الشائع تكديس كل المهام في قائمة default واحدة، فتتساوى الفاتورة العاجلة مع بريد تسويقي مؤجّل في نفس الصف. الأنظف تعريف عدة supervisors في config/horizon.php، كل واحد يخدم قائمة بأولوية مختلفة. مثلاً supervisor للقائمة high يحصل على عمّال دائمين وأولوية أولى للفواتير والدفع والتنبيهات الحسّاسة، وsupervisor آخر للقائمة default للمهام العادية، وثالث للقائمة low يعالج التقارير الثقيلة والتنظيف الليلي على مهل. حين تدفع مهمة تكتب queue('high') لتضمن التقاطها أولاً. مع استراتيجية auto، ينقل Horizon العمّال بين هذه القوائم حسب الازدحام مع احترام ترتيب الأولوية الذي حددته. هذا الفصل يحمي تجربة العميل: تأكيد الطلب يصله فوراً حتى لو كانت هناك مئات تقارير مجدولة تنتظر في قائمة منخفضة الأولوية.
لا تنسَ الإشراف على العملية نفسها
Horizon يدير العمّال، لكن من يدير Horizon؟ على السيرفر تحتاج مشرف عمليات مثل Supervisor أو خدمة systemd يبقي أمر horizon حيّاً ويعيد تشغيله إن مات أو بعد كل نشر. بدون هذا الإشراف، أول خطأ فادح يوقف Horizon كلياً وتتوقف كل الطوابير بصمت. بعد كل نشر جديد شغّل php artisan horizon:terminate فيُنهي Horizon العمّال الحاليين بلطف بعد إتمام مهامهم الجارية، ثم يعيد المشرف تشغيله بالكود الجديد، فلا تفقد أي مهمة نصف منفّذة.
المهام الفاشلة وإعادة المحاولة
لا مهمة تنجح دائماً، فنداء API خارجي قد يتعطّل لحظياً وقاعدة بيانات قد تُغلق اتصالاً تحت الضغط. Horizon يعرض تبويباً كاملاً للمهام الفاشلة يبيّن الاستثناء وأثر المكدّس ووقت الفشل، فتشخّص السبب بدل التخمين. اضبط عدد المحاولات عبر خاصية tries على المهمة، مع تأخير متصاعد بين المحاولات (backoff) فلا تقصف الخدمة المتعطّلة بطلبات متتالية، بل تنتظر ثوانٍ ثم دقيقة ثم أكثر. للمهام التي تلامس المال أو الطلبات، افصل بين الفشل العابر القابل للإعادة والفشل الدائم الذي يجب ألا يُعاد (مثل بيانات غير صالحة)، وارمِ استثناءً يوقف المحاولة فوراً في الحالة الثانية. راقب جدول failed_jobs بانتظام، فتراكم الفشل مؤشر على مشكلة بنيوية لا مجرد حظ سيّئ. من لوحة Horizon تعيد تشغيل مهمة فاشلة واحدة أو دفعة كاملة بضغطة بعد إصلاح السبب، فتتعافى بلا فقدان عمل.
الخلاصة العملية
ابدأ بتثبيت Horizon وافتح /horizon وراقب ثلاثة أرقام فقط في الأسبوع الأول: الإنتاجية، زمن التنفيذ، زمن الانتظار. إذا ارتفع الانتظار وحده فزد العمّال أو رقّ الباقة. إذا ارتفع التنفيذ فادخل الكود وأصلح الاستعلام البطيء. افصل مهامك إلى قوائم high وdefault وlow بحسب حساسيتها للوقت، واستخدم balance=auto مع minProcesses وmaxProcesses واضحين. ثبّت مشرف عمليات يبقي Horizon حيّاً، ونفّذ horizon:terminate بعد كل نشر. إذا بلغ vCPU سقفه ولم تتحسّن الإنتاجية، فالحل ترقية لا حشر عمّال، وترقيتك في خادم سحابي من كلاود فورية بلا انقطاع.


