"إذا أراد العامل أن يؤدي عمله بشكل جيد، فعليه أولاً أن يشحذ أدواته." - كونفوشيوس، "مختارات كونفوشيوس. لو لينجونج"
الصفحة الأمامية > برمجة > استخدام المشرف للتعامل مع تنفيذ أمر Symfony

استخدام المشرف للتعامل مع تنفيذ أمر Symfony

تم النشر بتاريخ 2024-11-01
تصفح:279

مقدمة

في هذا المنشور سوف نتعلم كيفية استخدام المشرف للتعامل مع تنفيذ أمر Symfony. في الأساس، سوف يسمح لنا المشرف بما يلي:

  • بدء الأمر تلقائيًا
  • إعادة تشغيل الأمر تلقائيًا
  • حدد عدد العمليات التي نريد أن يبدأها المشرف.

المشكلة

نلجأ أحيانًا إلى Unix crontab لأتمتة تنفيذ العمليات. قد ينجح هذا في معظم الأوقات ولكن قد تكون هناك مواقف يمكن أن تسبب فيها مشكلات.

لنتخيل أن لدينا جدول قاعدة بيانات يسجل إشعارات المستخدمين. يخزن الجدول المعلومات التالية:

  • مستخدم
  • نص
  • قناة
  • الحالة (في انتظار، تم الإرسال)
  • تم الإنشاء في
  • تم التحديث في

من ناحية أخرى، قمنا بتشفير أمر يتبع تنفيذه الخطوات التالية:

  • الاستعلام عن إشعارات الانتظار الأخيرة
  • يقوم بتكرار الإشعارات التي تم الاستعلام عنها و:
    • يرسل كل واحد إلى المستخدم المقابل.
    • تحديث حالة الإشعار من الانتظار إلى الإرسال

قمنا بتعيين هذا الأمر في crontab لنظام التشغيل Linux ليتم تشغيله بين الحين والآخر (دقيقة واحدة أو دقيقتين وما إلى ذلك). حتى الان جيدة جدا.

الآن لنتخيل أن العملية الحالية استعلمت عن 500 إشعار وعندما أرسلت 400، تبدأ عملية جديدة. وهذا يعني أن العملية الجديدة ستقوم بالاستعلام عن 100 إشعار لم يتم تحديثها بعد من خلال العملية الأخيرة بالإضافة إلى الإشعارات الجديدة:

Using Supervisor to handle a Symfony Command execution

يمكن أن يتسبب هذا في إرسال تلك الإشعارات المائة مرتين نظرًا لأن كلتا العمليتين قد استعلمتا عنها.

الحل

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

#[AsCommand(
    name: 'app:notification'
)]
class NotificationCommand extends Command
{
    private bool $forceFinish = false;

    protected function configure(): void
    {
        $this
            ->addOption('time-limit', null, InputOption::VALUE_OPTIONAL, 'Max time alive in seconds')
            ->addOption('time-between-calls', null, InputOption::VALUE_OPTIONAL, 'Time between every loop call')

        ;
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $this->forceFinish = false;
        pcntl_signal(SIGTERM, [$this, 'signalHandler']);
        pcntl_signal(SIGINT, [$this, 'signalHandler']);

        $timeLimit = $input->getOption('time-limit');
        $timeBetweenCalls = $input->getOption('time-between-calls');
        $dtMax = (new \DateTimeImmutable())->add(\DateInterval::createFromDateString("  {$timeLimit} seconds"));

        do{
           // Here we should execute a service to query and send notifications
           // ......

           sleep($timeBetweenCalls);
           $dtCurrent = new \DateTimeImmutable();

        }while($dtCurrent forceFinish);

        return Command::SUCCESS;
    }

    public function signalHandler(int $signalNumber): void
    {
        echo 'Signal catch: ' . $signalNumber . PHP_EOL;
        match ($signalNumber) {
            SIGTERM, SIGINT => $this->forceFinish = true,
            default => null
        };
    }
}

دعونا نشرح الأمر خطوة بخطوة:

  • تعلن طريقة التكوين عن خيارات الإدخال:

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

      يضبط متغير الفئة
    • forceFinish على صحيح
    • يستخدم مكتبة PHP pnctl لتسجيل الطريقة
    • signalHandler للتعامل مع إشارات Unix SIGTERM وSIGINT. يحصل على قيم خيارات الإدخال ويحسب الحد الأقصى للتاريخ الذي يمكن أن يكون فيه الأمر نشطًا حتى استخدام قيمة خيار
    • الحد الزمني
    • . تنفذ حلقة do-while الكود المطلوب للحصول على الإشعارات وإرسالها (لم يتم وضعها في الأمر، بل توجد تعليقات بدلاً من ذلك). بعد ذلك، يقوم بوضع الوقت الذي يحدده خيار
    • الوقت بين المكالمات
    • قبل المتابعة. إذا كان التاريخ الحالي (الذي يتم حسابه في كل تكرار للحلقة) أقل من الحد الأقصى للتاريخ وكان
    • forceFinish
    • خطأ، فستستمر الحلقة. وإلا سينتهي الأمر.
  • تقوم وظيفة
  • signalHandler

    بالتقاط إشارات SIGTERM وSIGINT Unix. SIGINT هي الإشارة المرسلة عندما نضغط على Ctrl C وSIGTERM هي الإشارة الافتراضية عندما نستخدم أمر الإيقاف. عندما تكتشفها الدالة signalHandler، فإنها تقوم بتعيين المتغير forceFinish على القيمة true بحيث، عند انتهاء الحلقة الحالية، سينتهي الأمر لأن المتغير forceFinish هو لم تعد كاذبة. يتيح ذلك للمستخدمين إنهاء العملية دون الحاجة إلى الانتظار حتى انتهاء الحد الأقصى للتاريخ.

  • تكوين المشرف

حتى الآن تم إنشاء الأمر. حان الوقت الآن لإعداد المشرف حتى يتمكن من التعامل معه. قبل البدء بالتكوين، يجب علينا تثبيت المشرف. يمكنك القيام بذلك باستخدام الأمر التالي:


sudo apt update && sudo apt install مشرف

sudo apt update && sudo apt install supervisor


مشرف الحالة sudo systemctl

sudo systemctl status supervisor
/etc/supervisor/conf.d

. لنقم بإنشاء ملف باسم notif.conf ولصق المحتوى التالي:
command=php /bin/console app:notifications --time-limit=120 --time-between-calls=10 المستخدم= نومبروكس = 1 التشغيل التلقائي = صحيح إعادة التشغيل التلقائي = صحيح اسم_العملية=%(اسم_البرنامج)s_%(process_num)02d

command=php /bin/console app:notifications --time-limit=120 --time-between-calls=10
user=
numprocs=1
autostart=true
autorestart=true
process_name=%(program_name)s_%(process_num)02d

    الأمر
  • : الأمر للبدء
  • المستخدم
  • : مستخدم يونكس الذي يقوم بتشغيل الأمر
  • numprocs
  • : عدد العمليات المطلوب تشغيلها
  • التشغيل التلقائي
  • : ما إذا كان سيتم تشغيل الأمر تلقائيًا
  • بدء التشغيل التلقائي
  • : ما إذا كان سيتم تشغيل الأمر تلقائيًا
  • process_name
  • : تنسيق اسم عملية الأمر Unix.
  • باستخدام هذا التكوين، سيتم تشغيل الأمر
app:notifications

لمدة أقصاها 120 ثانية، وسيظل في وضع السكون لمدة 10 ثوانٍ بعد كل حلقة. بعد مرور 120 ثانية أو تخزين إشارة يونكس مؤقتًا، سيخرج الأمر من الحلقة وينتهي. ثم سيبدأ المشرف في ذلك مرة أخرى. خاتمة

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

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

بيان الافراج تم نشر هذه المقالة على: https://dev.to/icolomina/using-supervisor-to-handle-a-symfony-command-execution-41h7?1 إذا كان هناك أي انتهاك، يرجى الاتصال بـ [email protected] للحذف هو - هي
أحدث البرنامج التعليمي أكثر>

تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.

Copyright© 2022 湘ICP备2022001581号-3