workerman定时任务必须在onworkerstart回调中注册,否则无法启动;耗时操作需异步化或后台执行,单次执行超50ms应中断,推荐用独立worker进程隔离任务以避免阻塞主事件循环。

Workerman定时任务执行时阻塞主循环导致连接响应变慢、心跳超时、新连接无法接入,必须让耗时操作脱离事件循环主线程运行。
确认定时任务是否在onWorkerStart中注册
打开你的Worker启动文件(如Timer.php或start_timer.php),检查Timer::add()是否写在$worker->onWorkerStart回调内部。如果直接写在全局作用域,定时器根本不会启动——Workerman只在Worker进程进入事件循环后才开始轮询定时任务队列。
这一步必须做,否则后续所有优化都无效。
把耗时操作移出回调函数主体
方法一:用AsyncTcpConnection发起异步HTTP请求
不要在Timer回调里用file_get_contents、curl_exec等同步网络调用。改用Workerman提供的异步客户端:
```php
Timer::add(5, function () {
$client = new AsyncTcpConnection('http://api.example.com');
$client->onConnect = function ($conn) {
$conn->send("GET /data HTTP/1.1\r\nHost: api.example.com\r\n\r\n");
};
$client->onMessage = function ($conn, $data) {
// 处理响应,不阻塞主循环
echo "received: " . strlen($data) . " bytes\n";
};
$client->connect();
});```
方法二:用exec + > /dev/null & 后台执行脚本
对完全无法异步化的命令(如ffmpeg转码、python数据清洗),用系统级异步脱钩:
```php
Timer::add(30, function () {
$cmd = 'php /path/to/clean_data.php > /dev/null 2>&1 &';
exec($cmd);
});```
【注意:不能用shell_exec或system,它们会等待命令结束才返回】
控制单次执行时长不超过50ms
第一步:在回调开头记录时间戳
```php
Timer::add(2, function () {
$start = microtime(true);```
第二步:在关键逻辑后判断耗时
```php
// 你的业务代码……
$used = microtime(true) - $start;
if ($used > 0.05) {
echo "WARNING: timer callback took {$used}s > 50ms\n";
}
});```
第三步:超过阈值立即中断后续非关键逻辑
例如数据库批量写入超过100条就拆成多次触发,避免一次锁表太久。
用独立Worker进程隔离定时任务
步骤一:创建专用定时Worker,不承载任何网络连接
```php
$timerWorker = new Worker();
$timerWorker->count = 1; // 强制单进程,避免重复执行```
步骤二:关闭该Worker的监听端口
不调用$timerWorker->listen(),也不绑定任何协议。它只负责跑onWorkerStart里的Timer::add,不处理任何连接事件。
步骤三:确保它在其他Worker之前定义
Workerman按代码顺序启动Worker,把$timerWorker放在最前面,能保证其PID为1,且不与其他业务Worker竞争CPU。
步骤四:在onWorkerStart中注册任务
```php
$timerWorker->onWorkerStart = function ($worker) {
Timer::add(10, [$this, 'doBackup']);
};```











