FrankenPHP重启失败主因是残留PHP进程抢占端口或socket,需用lsof/ps排查并精准kill messenger:consume等顽固进程,再清理/tmp/frankenphp.sock。

FrankenPHP 重启失败,大概率不是配置或代码问题,而是旧 PHP 进程没被彻底清理——尤其在 Symfony 应用里,php bin/console server:start、supervisord 管理的 worker、甚至未正确退出的 php-fpm 子进程都可能占着 socket 或端口,导致 FrankenPHP 新实例 bind 失败。
检查 FrankenPHP 是否真在监听端口
FrankenPHP 启动后默认监听 127.0.0.1:8080(或自定义端口),但残留进程可能已抢先绑定。直接测试比看 systemctl status 更可靠:
- 运行
lsof -i :8080(macOS / Linux)或netstat -ano | findstr :8080(Windows WSL),确认端口是否被非 FrankenPHP 进程占用 - 若输出中出现
php、php-fpm或console进程,说明有残留 - FrankenPHP 自身进程名通常是
frankenphp或php(取决于启动方式),别误杀它自己
识别 Symfony 场景下的典型残留源
Symfony 项目常带多种长驻进程,它们不会随 FrankenPHP 重启自动退出:
-
php bin/console messenger:consume—— 消息消费者,ignore_user_abort(true)+while(true)构成顽固后台进程 -
php bin/console web-server:run—— 已废弃但仍有人用,会独占8000端口,干扰 FrankenPHP 的 HTTP 路由调试 -
supervisord托管的php-fpm实例 —— 若你混用传统 FPM 和 FrankenPHP,supervisord可能还在拉起旧 FPM master -
php bin/console cache:warmup触发的子进程 —— 少数情况下因 SIGKILL 中断,留下孤儿进程
精准终止残留而不影响 FrankenPHP
别用 pkill php 这种暴力方式,它会干掉 FrankenPHP 主进程本身。按进程树和启动路径区分更安全:
立即学习“PHP免费学习笔记(深入)”;
- 查所有 PHP 进程及其命令行参数:
ps auxf | grep php,重点看COMMAND列是否含bin/console、messenger:consume、web-server:run - 逐个 kill:
kill -15 $(pgrep -f "messenger:consume")(先发 SIGTERM,给优雅退出机会) - 确认无残留:
pgrep -f "bin/console" | wc -l应返回0 - 如果仍有僵死进程(状态为
Z),用kill -9强制终结,但仅限明确识别出的残留项
FrankenPHP 启动前清空 Unix socket 文件
FrankenPHP 默认使用 Unix socket(如 /tmp/frankenphp.sock)与前端 Web 服务器通信。若上一次异常退出没删 socket,新实例会因 Address already in use 报错失败:
- 检查 socket 是否存在:
ls -l /tmp/frankenphp.sock - 手动删除:
rm -f /tmp/frankenphp.sock - 如果你改过 socket 路径,务必去对应目录执行相同操作;路径通常在
frankenphp.yaml或环境变量FRANKENPHP_SOCKET中定义 - 注意:不要删
/var/run/php/php*-fpm.sock—— 那是传统 FPM 的,与 FrankenPHP 无关
FrankenPHP 的“重启失败”往往卡在最基础的资源抢占环节,而不是配置或权限。每次重启前花 10 秒扫一遍 ps 和 lsof,比反复修改 frankenphp.yaml 有效得多。真正麻烦的是那些没日志、不报错、只静默失败的 socket 占用 —— 它们不会出现在 systemctl 状态里,但会让整个服务链路瘫痪。



















