FrankenPHP需在Caddyfile中显式配置php_worker指令启用worker模式,入口必须为public/worker.php,通过frankenphp stop-workers实现无感发布。

必须在 Caddyfile 中显式配置 php_worker 指令
FrankenPHP 默认不启用 worker 模式,哪怕 Symfony 项目本身支持,也只会走 per-request 流程。关键不是改 Symfony 代码,而是让 Caddy 主动拉起 PHP worker 实例。Caddyfile 中必须写成:
php_worker /var/www/myapp/public/index.php {
env APP_ENV=prod
max_requests 5000
}
注意三点:/var/www/myapp/public/index.php 必须是绝对路径;不能写成 ./public/index.php 或相对路径,Caddy 启动时 pwd 不可控;max_requests 建议设为 5000,避免单 worker 累积内存泄漏后僵死。
入口文件得用 public/worker.php,别硬套 index.php
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)) 包裹请求处理逻辑。
立即学习“PHP免费学习笔记(深入)”;
FRANKENPHP_WORKER=1 是环境变量,不是启动参数
别在命令行里加 --worker 或试图用 frankenphp-worker 单独启进程 —— 这样起的是孤立 CLI 进程,和 Caddy 主进程不联动,发布时无法优雅滚动。真正生效的方式是:
- 通过 Caddyfile 的
php_worker指令隐式启用 - 或在系统级环境变量中设
FRANKENPHP_WORKER=1(Docker 中用environment,宝塔面板在站点设置 → 环境变量里添加) -
frankenphp run启动(不是serve),否则 worker 不加载
验证是否生效:看日志有没有 Starting PHP worker pool with X workers;或者在控制器里打 getmypid(),连续两个请求 PID 相同即为成功。
发布时不能 reload,得用 frankenphp stop-workers
FrankenPHP 不响应 SIGHUP,caddy reload 只更新路由规则,不会让 worker 加载新代码。真正无感发布的流程是:
- 把新代码部署到独立目录(如
/releases/20261012-123456),软链current切过去 - 确保新目录下
public/index.php可读、var/cache可写、已执行composer install --no-dev --optimize-autoloader - 执行
frankenphp stop-workers—— 它不会杀主进程,只通知活跃 worker 处理完当前请求后退出,Caddy 自动拉起新 worker 加载新代码
漏掉 stop-workers 或手抖 kill -9,就会导致新旧代码混跑、缓存错乱、数据库连接句柄泄漏 —— 这些问题往往要等高并发时才暴露。



















