انتقل إلى المحتوى

إدارة الموارد

يقسّم Queuety التحكم بالموارد إلى أربع طبقات أساسية، مع إمكانية ضبط حجم مجموعة العمال فوقها.

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

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

وصف تكلفة وحدة واحدة من العمل

يمكن للمهام وخطوات سير العمل وإجراءات دخول الحالة جميعًا نشر تلميحات الموارد الثلاثة نفسها:

  • concurrency_group
  • concurrency_limit
  • cost_units

يصف concurrency_group وconcurrency_limit الضغط المشترك على نظام لاحق واحد. إذا كانت عدة معالجات تتصل بالمزوّد أو حساب API أو المستأجر نفسه، فيمكنها استخدام المجموعة نفسها كيلا يبدأ العمال عددًا كبيرًا من المهام في آن واحد.

يصف cost_units الوزن النسبي. قد يكون تحديث الذاكرة المؤقتة واستدعاء مزوّد كبير كل منهما «مهمة واحدة»، لكن لا ينبغي احتسابهما بالتساوي عندما تقرر ميزانية سير العمل أو قاعدة قبول العامل مدى أمان بدء مزيد من العمل.

PHP
final class CallProviderStep implements \Queuety\Step
{
    public function handle( array $state ): array
    {
        // ...
    }

    public function config(): array
    {
        return [
            'concurrency_group' => 'providers',
            'concurrency_limit' => 3,
            'cost_units' => 5,
        ];
    }
}

تنطبق الفكرة نفسها على المهام القابلة للإرسال عبر خصائص الفئة، وعلى عمليات الإرسال الفردية عبر PendingJob::concurrency_group() وPendingJob::cost_units().

وضع ميزانية لقوائم الانتظار ومجموعات المزوّدين المشتركة

لا يتعلق الضغط المشترك دائمًا بعدد بسيط من المهام المتزامنة. ففي بعض الأحيان، تكون التكلفة في الوزن الإجمالي للمهام الجاري تشغيلها.

يدعم Queuety ذلك عبر ميزانيات موزونة لقوائم الانتظار والمجموعات. تُحدد ميزانيات قوائم الانتظار باسم القائمة، أما ميزانيات المجموعات فتُحدد باستخدام concurrency_group، ما يسمح لمعالجات غير مترابطة بالمشاركة في الحد المشترك نفسه.

PHP
define( 'QUEUETY_RESOURCE_QUEUE_COST_BUDGETS', [
    'providers' => 20,
    'exports' => 8,
] );

define( 'QUEUETY_RESOURCE_GROUP_COST_BUDGETS', [
    'openai' => 12,
    'tenant:acme' => 6,
] );

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

يوفر ذلك تحكمًا مختلفًا عن concurrency_limit. قد يسمح المزوّد بثلاثة طلبات متزامنة، مع تخصيص عدد أقل من وحدات التكلفة الإجمالية للطلبات الأكبر مقارنةً بالأصغر.

إبقاء سير عمل واحد ضمن حدوده

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

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

يوفر Queuety حدودًا على مستوى سير العمل لهذا الغرض:

PHP
Queuety::workflow( 'research_run' )
    ->max_transitions( 20 )
    ->max_for_each_items( 12 )
    ->max_state_bytes( 32768 )
    ->max_cost_units( 40 )
    ->max_started_workflows( 8 )
    ->then( PlanResearchStep::class )
    ->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
    ->dispatch();

يمنع max_cost_units() التشغيل من استهلاك عمل موزون أكثر مما خُطط له. ويمنع max_started_workflows() العملية الرئيسية من التحول إلى شجرة غير محدودة من عمليات التشغيل الفرعية العليا. وتظل الضوابط الأخرى مهمة، لأن سبل الانفلات في تدفقات العمل لا تتساوى في التكلفة.

تعرض حالة سير العمل الحدود المحددة والاستخدام الحالي عبر الحمولة العامة budget، ما يتيح فحص التشغيل ما دامت تلك الحدود سارية.

السماح للعمال بتأجيل العمل عندما تكون العملية ممتلئة

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

هنا يأتي دور القبول المراعي للموارد. قبل بدء المهمة المستلمة، يمكن لـ Queuety النظر في ما يلي:

  • مجموعة التزامن المشتركة للمهمة
  • الميزانيات الموزونة لقائمة الانتظار ومجموعة المزوّد
  • سجل المدة الأخيرة والذاكرة القصوى المستخدمة للمعالج
  • هامش الذاكرة المتبقي للعامل الحالي
  • هامش الذاكرة المتبقي للحاوية أو المضيف الحالي
  • الوقت المتبقي في نطاق التشغيل لمرة واحدة

إذا كان العامل قريبًا جدًا من الحد الذي ضُبط له، يحرر Queuety المهمة بدلًا من بدء عمل يُرجّح ألا يكتمل بسلاسة.

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

جزء الحاوية أو المضيف اختياري. عند تفعيل QUEUETY_RESOURCE_SYSTEM_MEMORY_AWARENESS، يحاول Queuety قراءة بيانات ذاكرة cgroup أولًا، ثم يلجأ إلى /proc/meminfo على المضيفين Linux. وإذا لم تتوفر لقطة موثوقة على مستوى النظام، يواصل العامل استخدام الفحوصات الخاصة بالعملية.

توسيع مجموعات العمال مع مراعاة السعة

يسهل فهم مجموعات العمال الثابتة، لكنها تجبرك أيضًا على اختيار عدد واحد لفترات الهدوء والذروة معًا.

تتيح لك المجموعات التكيفية تعيين حد أدنى وحد أقصى بدلًا من ذلك:

سطر الأوامر
wp queuety work --queue=providers --min-workers=2 --max-workers=6

تحافظ العملية الرئيسية على تشغيل الحد الأدنى من العمليات الفرعية على الأقل، وتزيد عددها باتجاه الحد الأقصى عندما يرتفع تراكم المهام القابلة للاستلام، ثم تقلّص العدد بعد هدوء قائمة الانتظار طوال فترة السماح المحددة للخمول.

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

طريقة عملية لدمج الطبقات

تخيل سير عمل بحثيًا يخطط لاستدعاءات المزوّد، ويبدأ تدفقات عمل متخصصة، ثم يصوغ النتيجة.

يمكن للخطوة التي تتصل بالمزوّد نشر cost_units ومجموعة concurrency_group مشتركة كيلا تتسابق عدة عمال على استخدام المزوّد النموذجي نفسه. ويمكن لقائمة الانتظار حجز ميزانية موزونة لطلبات ذلك المزوّد. كما يمكن لسير العمل الرئيسي وضع حدَّين لـ max_cost_units() وmax_started_workflows() كيلا يسمح المخطط بنمو التشغيل إلى ما لا نهاية. وبعد ذلك، يمكن للعامل تأجيل استدعاء مزوّد مستلم حديثًا إذا أظهرت بيانات الذاكرة القصوى الأخيرة أن العملية أو الحاوية قريبة جدًا من حدها.

يوفر ذلك أربعة ضوابط منفصلة:

  1. وصف وزن العمل
  2. حجز سعة مشتركة لقائمة الانتظار أو المزوّد
  3. تحديد ما يمكن لتشغيل واحد إنشاؤه
  4. منع العامل المنشغل من بدء عمل أكثر مما ينبغي

مواضع واجهات API التفصيلية

هذه الصفحة نظرة عامة مفاهيمية.

للاطلاع على الخيارات العملية:

  • Workers يغطي سلوك القبول وثوابت وقت التشغيل
  • CLI يغطي أوامر مجموعات العمال الثابتة والتكيفية
  • Workflow Guardrails يغطي حدود سير العمل
  • Jobs يغطي بيانات الوظائف والمعالجات الوصفية
  • State Machines يغطي بيانات موارد الإجراءات والحالات الوصفية
  • API يسرد الأساليب الدقيقة وأشكال القيم المعادة