Symfony接入FrankenPHP 1.2 worker模式需Caddyfile显式配置php_worker绝对路径、使用public/worker.php入口、frankenphp run启动、设FRANKENPHP_WORKER=1环境变量,并通过stop-workers实现无感发布。

Symfony 项目接入 FrankenPHP 1.2 的 worker 模式,不是改几行代码就能“自动启用”,而是需要 Caddy 配置、入口文件、启动方式、环境变量四者协同生效。核心在于:FrankenPHP 默认不开启 worker,必须显式声明;Symfony 必须用适配常驻生命周期的入口;发布与缓存更新也得按新逻辑走。
必须在 Caddyfile 中写死 php_worker 指令
Caddy 不会自动识别 Symfony 是否支持 worker,它只认配置。漏掉这行,就永远是 per-request 模式:
- 路径必须是绝对路径,例如
/var/www/myapp/public/worker.php,不能写./public/worker.php或相对路径 - 必须指定
env APP_ENV=prod,否则容器可能加载开发配置,缓存失效 - 建议加上
max_requests 5000,防止内存泄漏累积导致 worker 卡死 - 完整示例:
php_worker /var/www/myapp/public/worker.php {<br> env APP_ENV=prod<br> max_requests 5000<br>}
入口文件必须用 public/worker.php(≥6.3)或手动适配
Symfony 官方自 6.3 起自带 public/worker.php,它是专为常驻设计的:只调用一次 $kernel->boot(),后续请求复用已初始化容器。直接拿 index.php 当 worker 入口会出问题:
- 首次请求成功,后续报
Class 'App\Kernel' not found—— autoloader 在请求间被重置 - 请求卡住、
frankenphp_busy_threads持续为 1 —— 入口没正确调用frankenphp_handle_request() - 若用旧版 Symfony,需手动创建
public/worker.php,结构参考官方模板:外层初始化$kernel,内层用frankenphp_handle_request(fn() => $kernel->handle($request))包裹处理逻辑
启动和发布必须用 frankenphp run + stop-workers
别用 frankenphp serve 或命令行加 --worker,这些起的是孤立 CLI 进程,和 Caddy 不联动:
立即学习“PHP免费学习笔记(深入)”;
- 必须用
frankenphp run启动,它才会读取 Caddyfile 并拉起 worker 实例 - 验证是否生效:看日志是否有
Starting PHP worker pool with X workers;或在控制器里打getmypid(),连续请求 PID 相同即成功 - 发布新代码时,
caddy reload只刷新路由,不会加载新 PHP 文件 —— 必须执行frankenphp stop-workers,它会让活跃 worker 处理完当前请求后优雅退出,Caddy 自动拉起新实例加载新代码
环境变量和缓存要配合长生命周期
worker 进程常驻,意味着所有状态(OPcache、容器、静态属性)都会跨请求保留:
-
FRANKENPHP_WORKER=1是环境变量,不是启动参数;宝塔用户可在站点设置 → 环境变量中添加,Docker 用户用environment:字段 - 别依赖
cache:clear命令 —— 它清的是磁盘缓存,但 worker 仍从内存加载旧类;真正生效要靠stop-workers+ 清var/cache+opcache_reset()(如更新了 vendor) - 确保
symfony/runtime已安装(composer require symfony/runtime),并确认public/index.php和worker.php都基于 Runtime 启动,避免环境误判



















