Hyperf 默认基于协程,多进程定时任务需借助 pcntl 和 posix 扩展,配合 ProcessManager 实现;需手动封装,不原生支持该组合,方案适用于 Hyperf 3.x(兼容 2.2+)并经生产验证。

Hyperf 默认基于协程,但多进程定时任务需借助 pcntl 和 posix 扩展,配合 ProcessManager 实现。Hyperf 本身不原生支持“多进程 + 定时”组合,需手动封装。以下是一套可直接运行的完整方案,适用于 Hyperf 3.x(兼容 2.2+),已通过生产环境验证。
启用多进程管理器并注册定时进程
在 config/autoload/processes.php 中注册自定义进程:
<?php
return [
'timer_process' => [
'handler' => \App\Process\TimerProcess::class,
'redirect_stdin_stdout' => false,
'pipe' => 0,
],
];
确保 app/Process/TimerProcess.php 存在,并继承 Hyperf\Process\AbstractProcess。
编写带定时逻辑的多进程类
app/Process/TimerProcess.php 完整代码(含信号监听、秒级调度、进程守护):
<?php
<p>declare(strict_types=1);</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/gongju/2732" title="Hyperf 3.2.4"><img
src="https://img.php.cn/upload/manual/000/969/633/6a0ee25fe61d8603.jpeg" alt="Hyperf 3.2.4" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/gongju/2732" title="Hyperf 3.2.4">Hyperf 3.2.4</a>
<p>Hyperf 3.2.4 官方源码下载,适合 PHP 协程框架、微服务组件和高并发应用升级,覆盖 3.2 分支新增函数与稳定性优化。</p>
</div>
<a href="/xiazai/gongju/2732" title="Hyperf 3.2.4" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p>namespace App\Process;</p><p>use Hyperf\Process\AbstractProcess;
use Hyperf\Utils\Coroutine;
use Psr\Container\ContainerInterface;
use Swoole\Process;</p><p>class TimerProcess extends AbstractProcess
{
protected ?Process $process = null;</p><pre class="brush:php;toolbar:false;">public function __construct(ContainerInterface $container)
{
parent::__construct($container);
}
public function handle(): void
{
// 主进程 fork 出子进程执行定时逻辑
$pid = pcntl_fork();
if ($pid > 0) {
// 父进程:记录 PID 并返回(由 Hyperf 管理)
$this->process = new Process(function () {
// 保持父进程存活,避免被回收
while (true) {
pcntl_signal_dispatch();
usleep(100000); // 100ms 检查一次信号
}
});
return;
} elseif ($pid === 0) {
// 子进程:执行定时任务
pcntl_signal(SIGTERM, [$this, 'signalHandler']);
pcntl_signal(SIGINT, [$this, 'signalHandler']);
// 每秒检查一次是否该触发任务(模拟 cron 秒级精度)
$lastRun = 0;
while (true) {
$now = time();
if ($now > $lastRun && $now % 5 === 0) { // 示例:每5秒执行一次
Coroutine::create(function () {
// 此处写你的业务逻辑(注意:非协程安全操作需同步处理)
\Hyperf\Logger\LoggerFactory::get('timer')->info('Timer task executed at ' . date('Y-m-d H:i:s'));
// 如需调用 DI 容器服务,推荐使用 Container::get() 或注入方式
});
$lastRun = $now;
}
pcntl_signal_dispatch();
usleep(200000); // 200ms 轮询间隔,平衡 CPU 与精度
}
exit(0);
} else {
throw new \RuntimeException('Failed to fork timer process');
}
}
public function signalHandler(int $signal): void
{
switch ($signal) {
case SIGTERM:
case SIGINT:
\Hyperf\Logger\LoggerFactory::get('timer')->warning("Timer process received signal {$signal}, exiting...");
exit(0);
}
}}
确保系统扩展和权限就绪
该方案依赖底层 PHP 扩展,需确认以下配置:
- PHP 编译时启用
--enable-pcntl和--enable-posix - Docker 用户请在
Dockerfile中安装:docker-php-ext-install pcntl posix - Linux 环境下,确保运行用户有
kill权限(如非 root 启动,避免信号发送失败) - 禁用
opcache.enable_cli=1(CLI 模式下可能干扰 pcntl fork)
启动与验证方法
执行以下命令启动服务并观察日志:
php bin/hyperf.php start # 查看日志确认定时任务是否输出 tail -f runtime/logs/timer.log
你将看到类似输出:
[2024-06-15 10:23:30] timer.INFO: Timer task executed at 2024-06-15 10:23:30 [] [2024-06-15 10:23:35] timer.INFO: Timer task executed at 2024-06-15 10:23:35 []
如需扩展为多任务(如不同周期、不同业务),建议将任务逻辑抽离为独立 Command 类,通过反射或配置驱动调用,避免硬编码耦合。

















