Hyperf通过单例CrontabDispatcherProcess进程统一调度并配合singleton+Redis锁实现多进程下定时任务不重复执行。需注册该进程、开启singleton、配置Redis mutex,确保各Worker共享调度逻辑与分布式锁,避免并发触发。

Hyperf 本身是协程框架,但通过 Process + Crontab 组合,可以安全、稳定地实现多进程环境下的定时任务调度。关键不是“多个定时任务进程”,而是让定时任务在多 Worker 进程中不重复执行,并支持高可用与分布式协调。
一、启用 Crontab 调度器进程(必须)
Hyperf 的定时任务由独立的 CrontabDispatcherProcess 进程统一调度,它运行在主进程之外,不依赖 Web Worker 数量,天然支持多进程部署场景:
- 编辑
config/autoload/processes.php,注册调度器进程:
return [
\Hyperf\Crontab\Process\CrontabDispatcherProcess::class,
];
- 该进程只启动一个实例,负责解析 cron 表达式、触发任务、管理锁,所有 Worker 进程共享同一份调度逻辑
- 无需为每个 Worker 启动单独的定时器,避免时间漂移和重复触发
二、配置定时任务并启用防重机制
默认情况下,定时任务类会在每个 Worker 进程里被加载,但实际执行需靠单例 + 分布式锁控制。否则多 Worker 会并发执行同一任务:
- 在任务类中开启
$singleton = true,确保同一时刻仅一个进程进入执行逻辑 - 配合 Redis 锁(推荐),防止跨机器重复:
#[Crontab(name: 'sync_order', rule: '0 * * * *', singleton: true)]
class SyncOrderTask extends AbstractCrontab
{
public array $mutex = ['type' => 'redis'];
<pre class="brush:php;toolbar:false;">public function execute(): void
{
// 业务代码,如调用 OrderService::sync()
}
}
-
mutex依赖已配置的 Redis 客户端;若未启用 Redis,可改用file类型(仅限单机) - 不加
singleton或mutex,在 4 Worker 场景下,每分钟该任务会被执行 4 次
三、确认多 Worker 下的行为是否正常
Hyperf 默认启动多个 Worker 进程(如 swoole.worker_num = 4),而定时任务不会因此翻倍执行。验证方式:
- 启动服务后观察日志:
[INFO] Crontab manager started with 1 tasks—— 注意是 “1 tasks”,不是按 Worker 数量翻倍 - 在
execute()中写入唯一标识日志,例如echo "PID:" . getmypid() . " | " . date('H:i:s') . PHP_EOL; - 多次执行后发现只有单个 PID 输出,说明防重生效;若多个 PID 同时输出,则检查
singleton和mutex是否配置正确
四、进阶:动态任务 + 多进程适配
若需从数据库动态加载任务(如运营后台增删规则),需注意多进程环境下配置同步问题:
- 使用
Swoole\Table或 Redis 存储任务元数据,所有 Worker 读取同一份配置 - 监听配置变更事件(如 Redis Pub/Sub),通知各 Worker 重新加载任务列表
- 避免在每个 Worker 中轮询数据库——会造成 N 倍 DB 请求压力
- 推荐方案:由
CrontabDispatcherProcess定期拉取最新任务列表,再广播给各 Worker(通过Server->sendMessage()或共享内存)
不复杂但容易忽略:定时任务不是“多进程跑多个定时器”,而是“一个调度器 + 多 Worker 协同防重”。只要调度器进程启用、单例与锁配置到位,Hyperf 就能天然支持生产级多进程定时调度。











