tp5.1本身不支持平滑重启,因其swoole:restart命令仅强制终止并重启进程,未集成swoole的sigusr1信号监听与onworkerstart动态加载机制;真正生效的热更新需手动配置reload_async、禁用opcache校验,并将tp初始化逻辑(如start.php引入、app实例重建、数据库连接等)全部置于onworkerstart中,确保每次worker重启都加载最新代码。

TP5.1 项目本身不支持平滑重启,必须依赖 Swoole 的进程模型和信号机制来实现;直接调用 php think swoole:restart 或 kill -9 是中断式重启,会丢请求、断连接、漏任务。
为什么 TP5.1 + Swoole 不能靠框架命令热重载
ThinkPHP 5.1 的 swoole:server 命令本质是封装了 swoole_http_server 启动逻辑,但未接管进程生命周期——它不监听 SIGUSR1,也不在 onWorkerStart 中动态加载控制器/模型。你改了 app/index/controller/Index.php,执行 php think swoole:restart 实际是先 kill -TERM 再 exec 新进程,TCP 连接立刻断开,WebSocket 心跳失效,正在执行的定时任务被丢弃。
- TP5.1 的自动加载器(
think\Loader)在 Worker 启动前就注册完毕,类文件早已载入内存,reload 不触发重新 require -
swoole:restart命令底层调用的是$server->shutdown(),非$server->reload(),属于强制终止 - 框架未设置
reload_async => true,也未禁用opcache.validate_timestamps=0,即使发信号也无效
真正生效的平滑重启必须手动配 Swoole 信号入口
要在 TP5.1 里实现 reload,得绕过框架命令,自己搭信号通道:主进程收到 SIGUSR1 后,逐个替换 Worker,新 Worker 在 onWorkerStart 里重新初始化 TP 环境——这才是 reload 生效的前提。
Swoole 6.1.1 是一个专为 PHP 设计的高性能事件驱动并发网络引擎。作为稳定版,它修复了编译时对 zlib 依赖的缺失及 curl 模块的内存安全风险。该版本支持协程、多线程与多进程架构,内置 TCP/HTTP/WebSocket 服务器,能够显著提升 PHP 在微服务、实时通信等场景下的执行效率与并发能力。
- 启动时显式设置:
$server->set(['reload_async' => true, 'worker_num' => 4]),否则SIGUSR1会阻塞主线程 - 在
onWorkerStart回调里重新执行 TP 初始化:require __DIR__.'/../thinkphp/start.php';,并重建App实例 - 确保 TP 的配置、路由、中间件全部在
onWorkerStart内加载,而非全局作用域 - 数据库连接、Redis 客户端等资源必须放在这里 new,否则旧连接残留会导致事务错乱或连接池泄漏
常见 reload 失效的三个硬坑
发了 kill -USR1 $(cat /var/run/swoole.pid) 却没更新代码?大概率掉进下面任一坑里:
-
SWOOLE_BASE模式下SIGUSR1被忽略——检查$server->mode,必须是SWOOLE_PROCESS(默认值),否则 reload 无响应 - OPcache 缓存 opcode 未失效:确认
opcache.validate_timestamps=On且opcache.revalidate_freq=0,否则即使文件变了,PHP 还跑旧字节码 - 类文件被提前 include:比如在
server.php顶部写了require 'app/index/controller/User.php',这个文件永远不会被 reload 触发重载
验证 reload 是否真生效的唯一可靠方式
别只看 ps aux | grep php 有没有新进程,要确认新 Worker 是否加载了新代码:
- 在
onWorkerStart里加一行:file_put_contents('/tmp/reload.log', date('Y-m-d H:i:s') . ' PID:' . getmypid() . ' md5:' . md5_file('app/index/controller/Index.php') . PHP_EOL, FILE_APPEND); - reload 前后对比
/tmp/reload.log中的md5值是否变化,PID 是否刷新 - 用
swoole_server::stats()查start_time和connection_num,确认连接数未归零、活跃连接持续存在
真正的平滑不是“看起来没挂”,而是旧连接不中断、新代码已执行、状态无残留——这三者缺一不可。任何一步漏掉,都可能在线上引发静默故障。










