facile-it / terminable-loop-command
一个Shell+PHP包装器,用于在守护进程或Kubernetes下循环运行Symfony控制台命令
Requires
- php: ^7.4 | ^8.0
- ext-pcntl: *
- symfony/console: ^4.4 | ^5.4 | ^6.0 | ^7.0
Requires (Dev)
- facile-it/facile-coding-standard: ^1.2
- jangregor/phpstan-prophecy: ^1.0.0
- phpspec/prophecy-phpunit: ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.10
- phpstan/phpstan-phpunit: ^1.3
- phpunit/phpunit: ^9.6.6
- symfony/phpunit-bridge: ^6.4
- vimeo/psalm: ^4.6
README
一个Shell+PHP组合,用于在守护进程或Kubernetes下循环运行Symfony控制台命令,而不是使用长时间运行的过程。
此软件包包含一个 shell 脚本 和一个 抽象的Symfony控制台命令类;您需要编写扩展该类的命令,并通过shell脚本启动它。理想情况下,脚本应作为容器入口点使用,或与Docker Compose、Kubernetes、supervisord
等一起启动。
安装
composer require facile-it/terminable-loop-command
使用方法
将所需执行的PHP脚本附加到shell脚本中,以循环启动
vendor/bin/terminable-loop-command.sh my_custom_command.php
... 其中 my_custom_command.php
启动您的命令类,该类必须扩展 AbstractTerminableCommand
(见此存储库中的测试存根)
使用常见Symfony应用的命令示例
在使用它时,请记住将 bin/console
作为第一个参数调用
vendor/bin/terminable-loop-command.sh bin/console my:command --optionA
... 其中命令类似于以下内容
<?php namespace Acme\Command; use Facile\TerminableLoop\AbstractTerminableCommand; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; class MyCommand extends AbstractTerminableCommand { public function __construct() { parent::__construct('my:command'); } protected function commandBody(InputInterface $input, OutputInterface $output): int { $this->setSleepDuration(60); // do something if (! $this->shouldSleep()) { // you can customize sleep duration during execution, even conditionally $this->setSleepDuration(0); } return 0; } }
为什么?
当运行PHP应用时,您可能会遇到需要持续运行的 后台命令。您可以尝试将其编写为长时间运行的过程,但它可能导致内存泄漏和其他问题。
使用这个小巧的Shell+PHP组合,您可以有一个简单的循环,
- 启动命令
- 执行某些操作
- 暂停指定的时间
- 关闭并重新启动
shell脚本拦截SIGTERM/SIGINT信号,因此当接收到这些信号时,PHP脚本将立即停止,但停止是优雅的,因为命令体的执行永远不会被截断。
这意味着您可以轻松获得 没有内存问题运行的PHP守护进程脚本;如果您在Kubernetes环境中运行此脚本,这将非常有用,因为编排器将负责运行脚本,同时它将在发生崩溃时应用适当的 重启策略。最后但并非最不重要的是,信号处理将与关闭请求很好地配合,例如在推出新部署期间。
工作原理
shell脚本非常基本,它会循环调用所需的命令,直到以不同的退出代码退出;它还会拦截SIGTERM/SIGKILL信号并将它们转发给PHP进程。
PHP命令设计为首先执行主任务(AbstractTerminableCommand::commandBody()
函数),然后暂停指定的时间,这可以在命令执行期间随时自定义;这很强大,因为您可以让命令逻辑决定两次命令执行之间的等待时间,甚至什么也不等待。
PHP类还优雅地处理信号,这意味着如果信号在commandBody()
函数期间接收,它将等待其完成;如果在睡眠阶段接收,它将立即终止它。如果由于信号终止,命令将以退出代码143
退出,这意味着我们是因为信号而退出的:这将中断shell脚本循环的执行,而不会被监督代理,如Kubernetes视为错误。