Swoole热更新本质是进程级替换而非代码重载,需配合max_request、USR1信号、opcache禁用或校验机制及文件监听实现。

热更新不是 reload,Swoole 本身不支持代码热载
直接说结论:swoole_http_server 或 Swoole\Server 启动后,PHP 代码变更不会自动生效——没有类似 Node.js 的 require.cache 清除机制,也没有内置的文件监听 + 重载逻辑。所谓“热更新”,其实是靠外部信号 + 进程管理配合实现的“伪热更”。
常见错误现象:kill -USR1 $pid 后服务没反应、worker 进程没重启、新代码依然不执行,本质是没配好信号处理或没理解 Swoole 的进程模型。
-
USR1信号只触发 worker 进程优雅退出(等待当前请求结束),不 reload 主进程或重新加载 PHP 文件 - PHP 脚本在 worker 启动时已全部解析编译(opcache 缓存 opcode),改完文件不重启进程,opcode 不会刷新
- 如果用了
opcache.enable=1(默认开启),即使重启 worker,旧 opcode 可能仍被复用,需额外清理
用 reload 命令 + max_request 控制 worker 生命周期
最稳妥的实操路径:让 worker 自动退出,由 master 拉起新实例,从而加载新代码。关键靠两个配合点:
- 启动时设
max_request(如['max_request' => 100]),让每个 worker 处理固定请求数后自动退出 - 配合
kill -USR1 $master_pid或调用$server->reload(),强制所有 worker 退出(不管是否达上限) - 确保业务逻辑里没有全局静态变量或
static属性残留,否则新 worker 可能读到旧状态
示例片段(启动时配置):
$server = new Swoole\Http\Server('0.0.0.0', 9501);
$server->set([
'max_request' => 100,
'daemonize' => false,
]);
开发期用 inotifywait 监听文件 + 自动 reload
本地调试时,手动发信号太慢,可用系统工具监听 PHP 文件变化后触发 reload。注意这不是生产方案,仅限 dev 环境。
- 依赖
inotify-tools包(Linux),macOS 需换用fswatch - 监听范围要精确:只监控
*.php,避免模板、日志、缓存文件误触发 - reload 前最好加个
sleep 0.1,防止文件还没写完就 reload 导致语法错误 - 别监听
vendor/或runtime/,否则 composer update 或日志写入会疯狂 reload
简短 shell 示例:
inotifywait -e modify,move_self,attrib -m ./app/ --format '%w%f' | while read file; do
[[ "$file" == *.php ]] && kill -USR1 $(cat swoole.pid) && sleep 0.1
done
opcache 配置必须关掉或设短 ttl
即使 worker 重启了,如果 opcache 还缓着旧字节码,新代码照样不生效。这是最容易被跳过的环节。
- 开发环境建议直接关掉:
opcache.enable=0(php.ini) - 如果必须开,至少设
opcache.validate_timestamps=1和opcache.revalidate_freq=1,否则默认 60 秒才检查文件修改 -
opcache.fast_shutdown=0更安全,避免某些析构逻辑在共享内存中残留 - 验证是否生效:访问
opcache_get_status()查看last_restart_time和opcache.hit_rate
顺手检查命令:
php -i | grep opcacheSwoole 的热更新本质是“进程级替换”,不是“代码级重载”。所有技巧都绕不开一个事实:PHP 是脚本语言,没有运行时类重定义能力,任何“热”都得靠进程退出 + 重新加载来兜底。漏掉
opcache 配置、误以为 USR1 会重读文件、或者在 worker 里长期 hold 住单例对象,都会让热更失效。










