Workerman 的 reload 命令仅平滑替换 Worker 子进程,重载 onMessage 等回调中动态加载的代码,但不生效于类定义、OPcache、静态配置等;其本质是 SIGUSR1 信号触发子进程逐个重启,非全量热更新。

Workerman 的 php start.php reload 确实能平滑重启,但只对“动态加载的代码”生效;类定义、配置、OPcache 缓存、define()、静态属性等完全不受影响——这不是 bug,是设计使然。
reload 命令到底重载了什么?
它不重启主进程,也不重新执行整个启动脚本,而是向主进程发送 SIGUSR1 信号,触发主进程逐个替换 Worker 子进程:
- 老 Worker 进程处理完当前请求后才退出(不丢连接、不中断 HTTP 流)
- 新 Worker 进程启动时会重新解析并执行
onMessage、onConnect、onWorkerStart等回调里的 PHP 代码 - 但仅限于“运行时动态加载”的部分:比如在
onMessage里用require './logic.php'引入的文件 - 写死在
onWorkerStart开头的$config = ['host' => 'old'];,reload 后仍是旧值
为什么改了代码 reload 后接口还是返回旧结果?
这是最常被误判为“reload 失效”的场景,本质是代码没走 reload 路径。常见原因:
-
app/controller/Api.php这类文件由 Composer autoloader 加载,属于“首次加载即固化”,reload 不会重新 require 它 -
opcache.enable_cli=1开启时,CLI 模式下 OPcache 不自动校验文件修改时间,新 PHP 文件仍执行旧字节码 - 用了
webman\support\Bootstrap或config/bootstrap.php预加载机制,这些在 Worker 初始化阶段就完成了,reload 不重跑 -
onWorkerStart中一次性require所有业务类,而不是在onMessage中按需加载
验证是否真生效:别信终端的 Reload success,查 php start.php status 输出的 Worker PID 是否变化,或翻 runtime/log/worker.log 是否有新 worker#0 started 记录。
Monitor 自动 reload 真的平滑吗?
Workerman 的 Monitor 组件监听文件变更后调用 posix_kill($pid, SIGINT),这和 reload 完全不是一回事:
-
SIGINT等效于 Ctrl+C,主进程立即终止所有 Worker,不等待当前请求完成 - 它不走
SIGUSR1+ 逐个替换路径,存在极小概率丢失正在处理的请求(压测中约万分之一失败率) - 内存超限触发的也是
SIGINT,同样不是平滑 - 生产环境必须关闭 Monitor 自动重启:
'enable_file_monitor' => false
reload 不行时,该用 restart 还是手动清理?
当遇到以下情况,reload 无意义,必须换方式:
- 修改了
Worker构造参数(如监听地址、$worker->count)、启动脚本逻辑 —— 必须php start.php restart(有秒级中断) - 改了类定义、
const、define()、静态属性 —— 只能restart或手动清 OPcache(opcache_reset()) - 想保留进程但刷新配置?可设
$worker->reloadable = false,配合onWorkerReload回调做运行时重载(如C(load_config()))
真正容易被忽略的是:reload 的“平滑”只对网络层连接和请求生命周期有效,对 PHP 运行时状态(符号表、OPcache、已加载类)完全无感——它不是热更新,只是子进程轮换。别指望它解决所有代码更新问题。

















