В этом посте мы узнаем, как использовать супервизор для управления выполнением команды Symfony. По сути, супервизор позволит нам:
Иногда мы прибегаем к unix crontab для автоматизации выполнения процессов. В большинстве случаев это может работать, но могут возникнуть ситуации, когда это может вызвать проблемы.
Предположим, у нас есть таблица базы данных, в которой регистрируются уведомления пользователей. В таблице хранится следующая информация:
С другой стороны, мы закодировали команду, выполнение которой следует следующим шагам:
Мы установили эту команду в crontab Linux так, чтобы она запускалась время от времени (1 минута, 2 минуты и т. д.). Все идет нормально.
Теперь представим, что текущий процесс запросил 500 уведомлений, а когда он отправил 400, запускается новый процесс. Это означает, что новый процесс запросит 100 уведомлений, которые еще не были обновлены последним процессом, а также новые:
Это может привести к тому, что эти 100 уведомлений будут отправлены дважды, поскольку оба процесса запросили их.
В качестве решения мы можем прибегнуть к использованию супервизора. Он будет поддерживать работу нашего процесса и перезапустит его при необходимости. Таким образом, мы сохраняем только один процесс и избегаем дублирования. Давайте разберем, как должна выглядеть команда:
#[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 }; } }
Давайте объясним команду шаг за шагом:
Метод configure объявляет параметры ввода:
Метод execute ведет себя следующим образом:
Функция signalHandler улавливает сигналы SIGTERM и SIGINT Unix. SIGINT — это сигнал, отправляемый, когда мы нажимаем Ctrl C, а SIGTERM — это сигнал по умолчанию, когда мы используем команду kill. Когда функция signalHandler обнаруживает их, она устанавливает для переменной forceFinish значение true, чтобы при завершении текущего цикла команда завершилась, поскольку переменная forceFinish равна true. уже не ложь. Это позволяет пользователям завершить процесс, не дожидаясь завершения максимальной даты.
На данный момент у нас создана команда. Теперь пришло время настроить супервизор, чтобы он мог с этим справиться. Прежде чем начать настройку, мы должны установить супервизор. Вы можете сделать это, выполнив следующую команду:
sudo apt update && sudo apt install supervisor
После установки вы можете убедиться, что супервизор запущен, выполнив следующую команду:
sudo systemctl status supervisor
Файлы конфигурации Supervisor размещаются в следующей папке: /etc/supervisor/conf.d. Давайте создадим файл с именем notif.conf и вставим в него следующее содержимое:
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
Давайте объясним каждую клавишу:
При такой конфигурации команда app:notifications будет выполняться максимум 120 секунд и переходить в режим сна в течение 10 секунд после каждого цикла. После прохождения 120 секунд или кэширования сигнала unix команда выйдет из цикла и завершится. Затем супервайзер запустит его снова.
Мы научились использовать супервизор, чтобы поддерживать выполнение команды без использования crontab. Это может быть полезно, когда процессы, запущенные crontab, могут перекрываться, что приводит к повреждению данных.
В последней книге, которую я написал, я показываю, как использовать Supervisor, чтобы обеспечить работу рабочих сообщений Symfony. Если вы хотите узнать больше, вы можете найти книгу здесь: Создание ориентированного на операции API с использованием PHP и Symfony Framework: пошаговое руководство
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3