mwstake / mediawiki-component-processmanager
提供后台进程管理系统
Requires
Requires (Dev)
- mediawiki/mediawiki-codesniffer: 39.0.0
- mediawiki/minus-x: 1.1.1
- php-parallel-lint/php-console-highlighter: 1.0.0
- php-parallel-lint/php-parallel-lint: 1.3.2
- phpunit/phpunit: ^8.5
README
此库允许您创建异步后台进程,这些进程可以从任何地方稍后访问,以检查进度和检索输出。当您启动进程时,它将被排队,并等待进程运行器执行它。
使用方法
进程基于提供给它的步骤工作,它将顺序执行步骤,将一个步骤的输出数据作为下一个步骤的输入,直到结束。最后一个步骤将返回其输出作为整个过程的输出。
步骤定义为 ObjectFactory
规范。从此类规范生成的对象必须是 MWStake\MediaWiki\Component\ProcessManager\IProcessStep
的实例。
示例步骤
class Foo implements IProcessStep { /** @var ILoadBalancer */ private $lb; /** @var string */ private $name; public function __construct( ILoadBalancer $lb, $name ) { $this->lb = $lb; $this->name = $name; } public function execute( $data = [] ): array { // Add "_bar" to the name passed as the argument in the spec and return it $name = $this->name . '_bar'; // some lenghty code return [ 'modifiedName' => $name ]; } }
创建进程
// Create process that has a single step, Foo, defined above // new ManagerProcess( array $steps, int $timeout ); $process = new ManagedProcess( [ 'foo-step' => [ 'class' => Foo::class, 'args' => [ 'Bar-name' ], 'services' => [ 'DBLoadBalancer' ] ] ], 300 ); $processManager = MediaWikiServices::getInstance()->getService( 'ProcessManager' ); // ProcessManager::startProcess() returns unique process ID that is required // later on to check on the process state echo $processManager->startProcess( $process ); // 1211a33123aae2baa6ed1d9a1846da9d
检查进程状态
一旦使用上述方法启动进程并获取进程 ID,我们就可以随时、从任何地方检查其状态,甚至从不同进程。
$processManager = MediaWikiServices::getInstance()->getService( 'ProcessManager' ); echo $processManager->getProcessInfo( $pid ); // Returns JSON { "pid": "1211a33123aae2baa6ed1d9a1846da9d", "started_at": "20220209125814", "status": "finished", "output": { /*JSON-encoded string of whatever the last step returned as output*/ } }
如果发生错误,响应将包含状态 error
,并显示异常信息和调用堆栈。
中断进程
有时,我们希望在步骤之间暂停,并重新评估返回的数据。
如果步骤实现 MWStake\MediaWiki\Component\ProcessManager\InterruptingProcessStep
而不是 MWStake\MediaWiki\Component\ProcessManager\IProcessStep
,则可以实现这一点。如果进程遇到此接口的实例,它将暂停处理并报告步骤返回的数据。
要继续进程,必须调用 $processManager->proceed($pid, $data)
。在这种情况下,$pid
是暂停进程的 ID,而 $data
是要传递给下一个步骤的任何修改后的数据。此数据将与从先前步骤(暂停进程的步骤)返回的数据合并。此调用将返回进程的 PID,它应与传递的相同(同一进程继续)。
同步执行步骤
这是该组件功能的一个分支。它允许您同步执行步骤,而无需启动进程。
$executor = new \MWStake\MediaWiki\Component\ProcessManager\StepExecutor( MediaWikiServices::getInstance()->getObjectNameUtils() ); // Optional, if all necessary data is passed in the spec, omit this $data = [ 'input' => 'data for the first step' ]; $executor->execute( [ 'foo-step' => [ 'class' => Foo::class, 'args' => [ $someArg1, $someArg2 ] ], 'bar-step' => [ 'class' => Bar::class, 'args' => [ $someArg1, $someArg3, $someArg4 ] ] ], $data );
注意
- 此组件需要一个数据库表,因此需要执行
update.php
。
设置
此机制具有以下主要部分
ProcessManager
- 管理进程的服务,允许启动进程并检查其状态processRunner.php
- 脚本从队列检索进程并执行它们。这是一个长期运行的脚本,应作为一个后台进程启动processExecution.php
- 实际运行单个进程的脚本。这是一个短期脚本,仅在单个进程执行期间存在
设置 processRunner.php
脚本 processRunner.php
应由 crontab 启动。有两种操作模式
- 执行队列中当前正在等待的进程
- 始终运行并等待将新进程添加到队列中。这与 MediaWiki 核心中的
runJobs.php
相同。
参数
- 第一个参数应该是 MediaWiki 核心中的
Mainetenance.php
文件的完整路径。这是由于该组件没有在代码库结构中预留专门的位置,可以安装在任何地方。 --wait
- 等待新的进程被添加到队列中。在此模式下,脚本将创建一个锁文件,防止其他运行器启动。当你只想同时运行一个运行器时,这很有用。如果它崩溃或被其他方式终止,锁文件将被删除,其他运行器可以启动。--max-jobs
- 在一次运行中要执行的最大进程数。当你想限制进程数量时,这很有用。--script-args
- 要传递给processExecution.php
脚本的参数。如果不清楚自己在做什么,请避免使用。
Crontab 示例:应作为 web 服务器用户或 root 执行。
* * * * * /usr/bin/php /var/www/html/mw/vendor/mwstake/mediawiki-component-processmanager/maintenance/processRunner.php /var/www/html/mw/maintenance/Maintenance.php --wait'
** 当指定 --wait
时,--max-processes
无效**
日志记录
通常,运行器将日志记录到调试日志机制的 ProcessRunner
通道中,但直接捕获脚本的输出(在 crontab 行中)并将其重定向到某个日志也很有用,这样我们就可以捕获运行器本身的任何错误。
实施中考虑的因素
这不是设置后台处理的好方法,但我们已经考虑到以下因素
- 我们希望有一个父进程为所有进程服务,这样它们就不会变成僵尸进程,并且我们可以捕获它们的任何输出
- 我们不希望在机器上设置任何单独的服务,如 Redis、RabbitMQ 等。理想情况下,不需要任何额外的设置,但需要 crontab 行。
- 我们不希望等待 crontab 执行进程,我们希望能够立即启动它,因此我们有了
--wait
参数 - 它必须在 Linux 和 Windows 上都工作