hyperf 中多进程定时任务需通过 @crontab 注解配合进程模型实现:默认在 worker 进程执行,开启多个 worker 可天然并发;设 singleton=false 且 ononeserver=false 可使同任务在每 worker 中运行;耗时任务应卸载至 task 进程执行以隔离资源。

Hyperf 中用注解配置多进程定时任务,核心在于 @Crontab 注解配合进程管理机制,但需注意:Hyperf 默认的 Crontab 是单进程调度器,要实现“多进程”定时任务,本质是让多个 Worker 进程(或独立的 Task 进程)各自执行不同任务,或通过 多 Crontab 实例 + 进程隔离 策略实现并发执行。不是靠一个注解自动开多个进程,而是靠框架调度+进程模型协同。
理解 Crontab 的运行载体:Worker 还是 Task 进程?
Hyperf 的 @Crontab 默认在 Worker 进程中执行,即所有定时任务都跑在已有的 HTTP/GRPC Worker 里。这意味着:
- 若开启 8 个 Worker,且多个
@Crontab触发时间重叠,它们可能被分配到不同 Worker 并发执行——这是天然的“多进程”基础; - 但同一任务(相同类+方法+表达式)默认只会在一个 Worker 中执行一次(由 Crontab 组件内部做主从选举,避免重复);
- 如需强制某任务在每个 Worker 都执行(例如本地缓存刷新),需设置
singleton=false并禁用去重逻辑(见下文)。
启用多实例并行:关闭单例 + 合理分配任务
若你希望同一定时逻辑在多个进程内同时运行(比如每 Worker 都采集一次本机指标),需显式关闭单例模式,并确保不依赖全局锁或共享内存冲突:
#[Crontab("*/10 * * * *", singleton: false, onOneServer: false)]
public function reportLocalMetrics(): void
{
$pid = getmypid();
logger()->info("Reporting metrics from worker #{$pid}");
// 执行仅与当前进程相关的操作(如读取 /proc/self/...)
}
-
singleton=false:取消主从选举,每个 Worker 都会尝试执行该任务; -
onOneServer=false:禁用分布式锁(适用于单机部署;集群部署需自行加 Redis 锁控制); - 务必确保任务逻辑无跨进程竞争(如不要写同一个文件、不要覆盖同一缓存 key)。如需聚合结果,应交由独立的 Task 进程或协程 Channel 汇总。
用 Task 进程承载耗时/隔离型定时任务
对于 I/O 密集或需资源隔离的定时任务(如批量导出、报表生成),推荐将执行逻辑卸载到 Task Worker,避免阻塞 HTTP Worker:
- 先定义一个 Task 类(如
ReportTask),实现handle()方法; - 在 Crontab 方法中调用
$this->container->get(TaskExecutor::class)->execute(ReportTask::class, [...]); - 确保
task_worker_num配置足够(如设为 4),以支持并发 Task 处理; - 这样既保持定时触发的便利性,又获得进程级隔离和可控并发能力。
验证与调试技巧
多进程定时任务容易因执行时机、进程生命周期或日志混杂而难排查,建议:
- 在 Crontab 方法开头记录
getmypid()和posix_getppid(),确认实际执行进程身份; - 使用
crontab:list命令查看已注册任务及其配置(php bin/hyperf.php crontab:list); - 临时把日志级别调至 debug,并过滤
crontab相关输出; - 集群环境务必测试
onOneServer=true是否真正生效(需 Redis 连接正常且键空间无干扰)。











