frankenphp worker模式下代码不更新的主因是reload仅重载caddy配置,不重启php worker进程;必须通过frankenphp stop-workers或启用watch:true触发sigterm使worker优雅退出并由caddy拉起新实例,同时确保路径正确、软链已切、opcache已清。

FrankenPHP worker 模式下代码不更新的常见原因
FrankenPHP 的 worker 进程一旦启动,就会常驻内存并复用 Symfony/Laravel 的容器、OPcache 编译结果和自动加载器状态。它不会自动监听文件变化,所以改完代码后 frankenphp reload 或 caddy reload 完全无效——这些命令只重载 Caddy 配置,不碰 PHP worker。
为什么 frankenphp reload 不触发代码重载
这个命令本质是调用 Caddy 的热重载机制,仅刷新路由规则、TLS 设置、静态文件路径等前端配置。PHP worker 进程本身完全不受影响,仍运行着旧版本的 public/index.php 和已编译的字节码。
- 错误现象:
frankenphp reload后访问接口仍是老逻辑,var_dump(__FILE__)显示路径没变,opcache_get_status()['scripts']里缓存的还是旧文件哈希 - 根本原因:FrankenPHP 没有内置类似 PHP-FPM 的
pm.max_requests自动轮换,也没有监听SIGHUP或SIGUSR2 - 唯一生效的 reload 场景:只在你修改了 Caddyfile 中的
php_worker路径或env变量时才有意义
worker 如何真正加载新代码
必须让旧 worker 主动退出,由 Caddy 拉起新实例,并确保新实例加载的是新路径下的 public/index.php。关键操作只有两个:
- 执行
frankenphp stop-workers:向所有活跃 worker 发送SIGTERM,它们会在完成当前请求后优雅退出;Caddy 随即拉起新 worker(前提是startup: 1或未设限) - 或启用
watch: true(FrankenPHP ≥ 1.2):监听项目根目录下.php、.yaml、.env等变更,自动触发SIGTERM;但注意它不监控vendor/,Composer 更新后仍需手动opcache_reset()或重启整个 FrankenPHP 进程
容易被忽略的路径与权限陷阱
即使执行了 stop-workers,新 worker 也可能静默失败,导致你以为“更新了”,其实还在跑旧实例。
-
php_worker必须写绝对路径,例如/var/www/current/public/index.php;写成./public/index.php或public/index.php会导致 worker 找不到入口,日志里只有一句模糊的"failed to start worker" - 软链接
current切换后,要确认新目录下public/index.php可读、var/cache可写、且已执行composer install --no-dev --optimize-autoloader - 如果用了自定义
APP_ENV,必须在 Caddyfile 中显式传入:php_worker /var/www/current/public/index.php { env APP_ENV=prod },否则新 worker 可能加载错环境配置
最常出问题的地方不在“怎么发信号”,而在于新 worker 启动时根本没加载到新代码——要么路径错了,要么软链没切,要么 OPcache 没清(尤其 vendor 更新后)。别假设它会自动感知变化,FrankenPHP 的 worker 是真·常驻,不是伪常驻。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











