FrankenPHP Worker模式默认热重载会引发Symfony缓存错乱,因多Worker并发写入同一var/cache目录,而Symfony缓存生成非进程安全;需禁用重载并为各Worker分配独立缓存子目录(如基于PID)。

FrankenPHP 的 Worker 模式默认启用热重载,这会干扰 Symfony 的缓存生成逻辑,导致 var/cache 下出现不一致的缓存文件(比如 ContainerXXXXX.php 被多个 Worker 并发写入或覆盖),最终引发 Class not found 或 Invalid container cache 错误。
为什么 Worker 重载会导致 Symfony 缓存错乱
FrankenPHP 在 worker 模式下,每个 PHP 进程独立运行并可能触发自己的 Kernel::boot() 流程;若开启 --reload-on-change(或通过 FRANKENPHP_WORKER_RELOAD_ON_CHANGE=1),文件变更会触发 Worker 重启 —— 但重启前旧 Worker 可能仍在写缓存,新 Worker 立即尝试读/写同一缓存目录,而 Symfony 的缓存生成(如 ConfigCache、ContainerBuilder)不是原子或进程安全的。
常见现象包括:
Warning: file_put_contents(var/cache/dev/Container.../App_KernelDevDebugContainer.php): failed to open stream: No such file or directory- 缓存文件内容截断、PHP 语法错误、类定义缺失
- 开发中改一个 Twig 模板,整站报
ServiceNotFoundException
关闭 Worker 重载的两种可靠方式
必须确保重载机制完全禁用,不能只靠环境变量“覆盖”,要从启动入口和配置两层拦截:
立即学习“PHP免费学习笔记(深入)”;
- 启动命令中显式添加
--no-reload:例如frankenphp worker --no-reload --env=dev - 在
frankenphp.yaml中设置worker.reload_on_change: false(注意:该配置仅在 FrankenPHP v1.1.0+ 生效;旧版本忽略此字段) - 彻底移除环境变量干扰:
FRANKENPHP_WORKER_RELOAD_ON_CHANGE必须未设置,或明确设为0(设为false或空字符串无效)
Symfony 缓存目录需支持并发安全写入
即使关掉重载,多个 Worker 进程仍可能同时冷启动(比如高并发首请求),因此不能依赖默认缓存路径。推荐做法:
- 为每个 Worker 进程分配独立缓存子目录,例如基于 PID 或随机哈希:
var/cache/dev-worker-= getmypid() ?> - 在
src/Kernel.php中重写getCacheDir():
public function getCacheDir(): string
{
if ($this->environment === 'dev' && \extension_loaded('posix')) {
$pid = posix_getpid();
return $this->getProjectDir().'/var/cache/'.$this->environment.'-worker-'.$pid;
}
return parent::getCacheDir();
}
注意:不要用 uniqid() 或时间戳——Worker 启动间隔短时易冲突;PID 是最轻量且进程唯一的标识。
验证是否真正生效
光改配置不等于问题消失,务必检查运行时行为:
- 启动后查看日志,确认无
Reloading worker due to file change类提示 - 执行
ps aux | grep frankenphp,观察 Worker 进程是否稳定存在(不频繁启停) - 访问应用多次,检查
var/cache下是否生成多个以-worker-结尾的目录,且各自包含完整的Container*.php - 手动 touch 一个控制器文件,确认 Web 页面不闪退、无缓存异常报错
最容易被忽略的是:本地开发用 symfony server:start 时,它底层可能仍调用 FrankenPHP 的默认 Worker 启动逻辑,此时 --no-reload 必须透传进去,否则配置文件里的设置会被绕过。



















