正确做法是调用 init() 而非 run():加载 autoload、Yii.php、bootstrap.php 和配置后,执行 (new yii\web\Application($config))->init() 完成组件注册与别名初始化,避免依赖 HTTP 生命周期的 run() 导致报错或卡死。

直接在Worker启动前加载Yii2初始化代码,但必须调用 init() 而非 run()
Workerman是常驻进程,不能像PHP-FPM那样每次请求都完整启动Yii2应用。强行调用 (new yii\web\Application($config))->run() 会报错或卡死,因为 run() 依赖HTTP请求生命周期(如 $_SERVER、响应输出等),而Workerman里没有这些上下文。
正确做法是只执行框架初始化阶段:载入自动加载器、Yii类、配置文件,然后调用 init() —— 它只注册组件、设置别名、初始化日志和事件,不启动请求循环。
- 确保
require(__DIR__.'/../vendor/autoload.php')和require(__DIR__.'/../vendor/yiisoft/yii2/Yii.php')已加载 - 必须显式引入
bootstrap.php文件(如require(__DIR__.'/../common/config/bootstrap.php')),否则组件别名、行为等可能失效 -
$config合并顺序要和Web入口一致,尤其注意main-local.php应在最后覆盖,避免敏感配置被线上值误覆盖 - 调用
(new yii\web\Application($config))->init()后,Yii::$app就可用了,所有已注册组件(如db、cache)都能直接取用
数据库连接必须启用 persistent,否则高并发下会快速耗尽MySQL连接数
Yii2默认的 yii\db\Connection 在每次 open() 时创建新连接,Workerman常驻特性会让连接长期持有却不释放——表面看没问题,但实际每个Worker子进程都会维持一套独立连接池,且不会自动复用或回收空闲连接。
不加 persistent => true 的后果:4个Worker进程 × 每个进程最多10个连接 = 40个MySQL连接被长期占用;若再开多个端口(如WebSocket + HTTP API),很容易触发 Too many connections 错误。
- 在
db组件配置中明确添加'persistent' => true - 同时建议设置
'attributes' => [PDO::ATTR_TIMEOUT => 5],防止网络异常导致连接卡死 - 不要依赖
Yii::$app->db->close():Workerman里没“请求结束”概念,手动关连接反而可能导致后续查询失败 - 验证是否生效:启动后执行
Yii::$app->db->getIsActive(),返回true即表示连接已建立且活跃
debug组件、request、response 等Web专属组件必须禁用或跳过加载
Workerman环境没有 $_GET、$_POST、HTTP头、输出缓冲等,任何依赖这些的组件在初始化时就会抛出异常。最典型的是 debug 和 log 中的 FileTarget(若路径不可写也会崩),还有 request 组件尝试读取 $_SERVER['REQUEST_URI'] 直接报 Undefined index。
- 在合并配置前,从
$config中 unset 掉'debug'、'request'、'response'、'urlManager'等键 - 如果项目用了
log组件,确保其 targets 不依赖Web上下文(例如避免BrowserTarget),推荐只保留FileTarget或SyslogTarget - 切勿在
bootstrap.php中调用Yii::setAlias('@web', ...)这类基于URL的别名,Workerman里无“web根路径”概念 - 若需记录调试信息,改用
file_put_contents('/tmp/workerman.log', ...)或直接调用Yii::info()(只要 log 组件本身能初始化)
全局状态共享是双刃剑:静态属性和单例在Worker内跨请求有效,但要注意线程安全
Workerman每个子进程内,所有请求共享同一份内存空间。这意味着 Yii::$app 是单例,static $counter = 0 在多次消息处理中会持续累加——这既是优势(比如缓存DB连接),也是隐患(比如未重置的状态污染后续请求)。
最容易被忽略的是:ActiveRecord模型里的静态缓存(如 findBySql 结果)、自定义静态属性、甚至第三方SDK内部的静态连接池,都可能在长连接场景下越积越多,最终OOM或返回脏数据。
- 避免在模型类中使用
public static $cache = []存储业务数据;改用Yii::$app->cache并设合理过期时间 - 如果必须用静态变量,务必在每次处理逻辑开头做清理(如
self::$tempData = []) - Redis/MySQL连接由Yii2组件管理即可,不用自己 new Client + static store;组件本身已处理复用与断线重连
- 对关键共享资源(如共享内存、信号量),优先使用Workerman原生的
Worker::$connections或Timer,而非自行实现


















