symfony 的 cache:clear 在 frankenphp worker 模式下失败,根本原因是常驻进程导致 opcache 不自动失效、缓存文件被并发读写、路径解析错位;需停进程+清磁盘+重载worker+禁用warmup才能真正生效。

为什么 Symfony 的 cache:clear 在 FrankenPHP 下会失败
直接执行 php bin/console cache:clear 会报错或清不干净,根本原因是 FrankenPHP 的 worker 模式让 PHP 进程常驻内存,而 Symfony 缓存系统默认依赖文件时间戳和 opcache 失效机制——但 worker 进程里 opcache_invalidate() 不自动触发,且 var/cache 目录可能被多个 worker 实例并发读写。
- Classic 模式(非 worker)下该命令基本可用,因为每次 CLI 调用都是全新进程,缓存重建干净
- Worker 模式下,即使你手动删了
var/cache/prod,worker 仍可能从内存中继续使用旧的缓存类或配置 - Symfony 6.4+ 默认启用
cache.adapter.filesystem,但 FrankenPHP 的realpath()行为与 FPM 有细微差异,导致缓存路径解析错位
如何让 cache:clear 真正生效(含 Docker 场景)
必须绕过“单纯删文件”这个动作,转为强制重载整个 worker 生命周期 + 清理磁盘 + 刷新 opcache。
- 先停掉 FrankenPHP:发送
SIGTERM或执行kill $(cat /tmp/frankenphp.pid)(若你用了 pidfile) - 再清缓存:
php bin/console cache:clear --env=prod --no-warmup - 手动清除 opcache:
php -r "opcache_reset();"(注意:这仅对当前 CLI 进程有效,不影响 worker) - 最关键一步:启动 FrankenPHP 时加
--env=prod --no-debug参数,并确保CACHE_WARMER_ENABLED=0环境变量未被设为1,否则 warmup 会抢在 worker 初始化前写入旧缓存 - Docker 用户注意:
var/cache必须挂载为 volume,否则容器重启后缓存目录消失,worker 启动时报Cache directory does not exist
worker 模式下缓存自动刷新的替代方案
靠人工 cache:clear 不现实,尤其在 CI/CD 或灰度发布场景。更稳的做法是把缓存生命周期交给 FrankenPHP 自身控制。
- 在
Caddyfile中启用frankenphp_worker指令,并设置max_requests 500(而非默认0),让 worker 主动回收并重建缓存 - 用
Symfony Runtime配合 FrankenPHP:在public/index.php开头插入if (getenv('FRANKENPHP_WORKER')) { $_SERVER['APP_ENV'] = 'prod'; },避免环境误判导致缓存路径错乱 - 禁用
cache.system的文件监听(framework.cache.system设为cache.adapter.psr6并指向cache.adapter.redis),把缓存状态外移,worker 只负责读,不负责生成
容易被忽略的细节:OPcache + APCu 在 worker 中的真实行为
很多人以为开了 opcache.enable_cli=1 就能解决 CLI 缓存问题,其实 FrankenPHP 的 CLI 模式(frankenphp php-cli)并不加载 php.ini 里的 OPcache 配置,它只认编译时内置的值。
- 验证方式:
frankenphp php-cli -i | grep opcache,你会发现opcache.enable是Off,哪怕你在系统 php.ini 里开了 - 正确做法:用
frankenphp php-cli -d opcache.enable=1 script.php显式开启,或改用frankenphp php-server启动后通过 HTTP 触发 warmup - APCu 在 worker 中默认不可用,需额外加
--enable-apcu编译参数,官方二进制没开;Docker 镜像里要自己docker-php-ext-install apcu
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











