germanovn / php-overdaemon
PhpOverDaemon — 使用 PHP 编写的守护进程管理解决方案
1.0.1
2023-02-28 11:26 UTC
Requires
- php: >=8.2.0
- ext-pcntl: *
- psr/log: ^3.0.0
Requires (Dev)
- phpunit/phpunit: ^9.6
This package is auto-updated.
Last update: 2024-09-29 10:28:06 UTC
README
大家好!在集成消息代理的过程中,我不得不将一些 PHP 代码片段转换为守护进程。这个仓库包含一个由 Composer 安装的包。该包的目的是保持您编写的守护进程正常运行,并管理它们以及收集日志。
安装
composer require germanovn/php-overdaemon
使用
要使用 OverDaemon,需要
- 创建一个实现
GermanovN\OverDaemon\DaemonGate\InferiorDaemonRepository
接口的守护进程仓库类; - 拥有一个您想要更好地控制的守护进程。
示例
您的守护进程仓库可能看起来像这样
<?php namespace MyApp\Daemon; use GermanovN\OverDaemon\DaemonGate\InferiorDaemon; use GermanovN\OverDaemon\DaemonGate\InferiorDaemonRepository; class MyInferiorDaemonRepository implements InferiorDaemonRepository { private array $daemonCollection; public function getAll(): array { return $this->daemonCollection; } public function add(InferiorDaemon $daemon): void { $this->daemonCollection[] = $daemon; } public function count(): int { return count($this->daemonCollection); } }
您的守护进程可能看起来像这样
<?php namespace MyApp\Daemon; use Exception; use GermanovN\OverDaemon\Daemon\Daemon; use GermanovN\OverDaemon\Daemon\StoppableDaemon; use GermanovN\OverDaemon\DaemonGate\InferiorDaemon; class MyDaemon extends StoppableDaemon implements InferiorDaemon { private int $pid; /** * @throws Exception */ public function devour(array $args = null): int { $this->pid = $args['pid']; try { // бесконечный цикл выполнения while ($this->isRunningDaemon()) { // получение задачи $execTime = $this->getSomeLongTask(); if (null === $execTime) { $this->stopDaemon(SIGSTOP); continue; } // выполнение задачи $this->logger->debug("Start '" . $this->name() ."' PID: {$this->pid}"); $this->doTask($execTime); $this->logger->debug("End '" . $this->name() ."' PID: {$this->pid}"); } return Daemon::EXIT_CODE_SUCCESS; } catch (Exception $e) { $this->logger->error( sprintf('Code: %d. Message: %s', $e->getCode(), $e->getMessage()), $e->getTrace() ); return Daemon::EXIT_CODE_ERROR; } } /** @throws Exception */ private function getSomeLongTask(): ?int { $execTime = random_int(1, 10) * 10; return $execTime >= 90 ? null : $execTime; } private function doTask(int $task): void { for ($i = 0; $i < $task; $i++) { $this->logger->debug($this->name() . " PID: {$this->pid} " . $i); usleep(10000); } } public function beforeDevour(): bool { // в это методе можно обновить подключение к вашей БД return true; } public function afterDevour(): void { } public function name(): string { return self::class; } }
请注意,示例中使用了抽象类 \GermanovN\OverDaemon\Daemon\StoppableDaemon
。这个类存在是为了在接收到 POSIX 信号时正确地终止。默认情况下处理以下信号:
- SIGINT - 来自终端的中断信号 (Ctrl-C);
- SIGTERM - 终止信号 (默认的 kill 工具信号)。
OverDaemon 使用示例
<?php // src/Command/OverDaemonCommand.php // Перехват сигналов pcntl_async_signals(true); // Передача обработки сигналов в SigHandler $sigHandler = SigHandler::instance(); pcntl_signal(SIGINT, [$sigHandler, 'handle']); pcntl_signal(SIGTERM, [$sigHandler, 'handle']); pcntl_signal(SIGHUP, [$sigHandler, 'handle']); $repository = new MyInferiorDaemonRepository(); $repository->add(new MyDaemon()); $daemon = new OverDaemon( new DaemonConfig(), $repository, $sigHandler ); echo $daemon->devour();
运行测试
vendor\bin\phpunit tests