不能直接覆盖代码再等新请求生效,因为frankenphp worker进程将php文件编译进opcache并长期驻留内存,软链接切换后旧字节码仍有效,新请求复用旧缓存,导致fatal error、类找不到或配置不更新。

必须用 frankenphp stop-workers 触发旧 worker 优雅退出,不能靠 kill、reload 或改代码后静默等待
为什么不能直接覆盖代码再等新请求生效
FrankenPHP 的 worker 进程会把 PHP 文件编译进 OPcache 并长期驻留内存。即使你用 ln -sf 切换了 /var/www/current 软链接,旧字节码仍有效,opcache_get_status()['scripts'] 里还能看到旧路径的文件。新请求进来时,worker 复用的是旧缓存,不是新代码——这会导致类找不到、函数重复声明等 Fatal error。
常见错误现象包括:
Fatal error: Cannot declare class App\Controller\Home, because the name is already in use-
Class 'App\Models\User' not found(但文件明明存在且路径已更新) - 修改了
config/app.php,但config('app.name')返回的仍是旧值
frankenphp stop-workers 的正确执行条件
这个命令不是“重启服务”,而是向所有活跃 worker 发送“完成当前请求后退出”信号。它依赖本地 Unix socket 通信,默认路径为 /tmp/frank,因此:
- 必须在 FrankenPHP 主进程所在的同一台宿主机上执行,不能在另一个容器或远程 SSH 会话里调用
- 确保
FRANKENPHP_WORKER=1已设为环境变量(不是 CLI 参数),否则该命令无 worker 可通知 - Caddyfile 中的
php_worker必须指向public/index.php的绝对路径,例如/var/www/current/public/index.php;写相对路径如./public/index.php会导致 worker 启动失败且无明确报错,只在日志里有failed to start worker
发布流程必须严格分步:换代码 → 清缓存 → 通知退出
三步缺一不可,顺序也不能颠倒:
- 先部署新代码到独立目录(如
/var/www/myapp/releases/20261013-010000),确保public/index.php可读、var/cache可写、已运行composer install --no-dev --optimize-autoloader - 执行软链接切换:
ln -sf /var/www/myapp/releases/20261013-010000 /var/www/current - 清 OPcache:
opcache_reset()或通过frankenphp opcache-reset(若 CLI 可用);同时清 Laravel/Symfony 的配置与路由缓存(php artisan config:clear等) - 最后执行:
frankenphp stop-workers—— 此刻新请求会由新 worker 加载新代码处理
容易被忽略的一点是:max_requests 参数虽能自动触发 worker 轮替,但它只是兜底机制,不能替代主动通知。设为 5000 意味着最多要等 5000 个请求才能全量更新,而 stop-workers 是秒级生效的强制刷新点。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











