在这篇文章中,我们将学习如何使用supervisord来处理symfony命令的执行。基本上,supervisord 将允许我们:
有时我们会使用 unix crontab 来自动执行进程。这可能在大多数情况下有效,但在某些情况下可能会导致问题。
假设我们有一个记录用户通知的数据库表。该表存储以下信息:
另一方面,我们编写了一个命令,其执行遵循以下步骤:
我们在 Linux crontab 中设置此命令每隔一段时间运行一次(1 分钟、2 分钟等)。到目前为止,一切都很好。
现在让我们想象一下当前进程已经查询了 500 个通知,当它发送了 400 个通知时,一个新进程启动。这意味着新进程将查询上一个进程尚未更新的 100 条通知以及新的通知:
这可能会导致这 100 个通知发送两次,因为两个进程都查询了它们。
作为解决方案,我们可以求助于使用supervisor。它将保持我们的进程运行并在需要时重新启动它。这样,我们只保留一个进程并避免重叠。让我们分析一下命令应该是什么样子:
#[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 变量为不再虚假。这允许用户终止进程,而不必等到最大日期完成。
到目前为止,我们已经创建了命令。现在是时候设置主管了,以便它可以处理它。在开始配置之前,我们必须安装supervisor。您可以运行以下命令来完成此操作:
sudo apt update && sudo apt install supervisor
安装后,您可以通过执行以下命令来确保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 信号后,该命令将退出循环并完成。然后,主管将再次启动。
我们已经学会了如何使用supervisor来保持命令运行而不必使用crontab。当 crontab 启动的进程可能重叠并导致数据损坏时,这非常有用。
在我写的上一本书中,我展示了如何使用 Supervisor 来保持 symfony Messenger Worker 的运行。如果您想了解更多信息,可以在这里找到这本书:使用 PHP 和 Symfony 框架构建面向操作的 Api:分步指南
免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。
Copyright© 2022 湘ICP备2022001581号-3