Hyperf 中实现多进程定时任务并支持优雅停止,关键在于监听 SIGTERM/SIGINT 信号,通过 pcntl_async_signals(true) 和 pcntl_signal 注册回调设置退出标志,主循环中定期检查并干净退出;推荐用 sleep() 而非 Timer::tick() 以确保信号及时响应。

Hyperf 中实现多进程定时任务并支持优雅停止,关键在于正确监听系统信号(如 SIGTERM、SIGINT),并在收到信号后主动退出子进程,避免任务被强制中断导致数据不一致或资源未释放。
使用 ProcessManager 启动多进程定时任务
Hyperf 提供了 Hyperf\Process\ProcessManager 管理自定义进程。需继承 Hyperf\Process\AbstractProcess,在 handle() 中写循环逻辑,并配合信号监听。
- 在
handle()内使用while (true)+sleep()或Timer::tick()实现定时调度 - 务必在循环开始前注册信号处理器,否则子进程无法响应外部终止指令
- 避免在
handle()中阻塞过久(如长耗时同步 I/O),否则信号可能延迟响应
在子进程中监听 SIGTERM 和 SIGINT
Hyperf 子进程默认不自动处理终止信号,需手动调用 pcntl_signal() 并启用 ticks(PHP 8.1+ 推荐用 pcntl_async_signals(true))。
- 在
handle()开头启用异步信号:pcntl_async_signals(true); - 注册回调:
pcntl_signal(SIGTERM, [$this, 'signalHandler']);,同理注册SIGINT - 定义
signalHandler()方法,设置标志位(如$this->shouldExit = true;),**不要在信号回调里直接 exit 或 die** - 主循环中定期检查该标志,干净退出当前迭代并 return
确保定时器与信号协同工作
若使用 Hyperf\Timer\Timer 的 tick() 或 after(),注意其底层基于 EventLoop,而自定义进程默认不启动协程调度器。推荐用原生 sleep() 控制间隔,更可控且兼容信号。
- 错误做法:在
tick()回调中执行业务,但主进程未监听信号 → 无法及时停止 - 正确做法:主循环中
sleep(5),每次醒来先检查$this->shouldExit,再决定是否执行任务 - 如必须用 Timer,需在进程内手动启动
Coroutine::create()并运行Event::wait(),但复杂度高,一般不推荐
配置与启动注意事项
在 config/autoload/processes.php 中注册进程类,并确保 enable 为 true;部署时通过 php bin/hyperf.php start 启动,停止时用 kill -SIGTERM {pid} 或 Ctrl+C 触发信号。
- 进程类需加
public $watcher = false;(默认值),避免被 Hyperf 进程管理器误杀 - 生产环境建议配合 Supervisor 使用,其可转发
SIGTERM到子进程 - 调试时可用
ps aux | grep php查看进程状态,确认是否残留


















