在这篇文章中,我们将学习如何使用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 < $dtMax && !$this->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 <your_project_folder>/bin/console app:notifications --time-limit=120 --time-between-calls=10 user=<your_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:分步指南
以上是使用 Supervisor 处理 Symfony 命令执行的详细内容。更多信息请关注PHP中文网其他相关文章!