frankenphp worker崩溃后默认不自动重启,因其主进程不监控子进程存活状态,也不注册sigchld信号处理器;恢复需显式配置restart: always、worker脚本内加try/catch、并配合systemd三层保障。

FrankenPHP Worker崩溃后默认不自动重启
不会。FrankenPHP 主进程本身不监控 Worker 进程的存活状态,也不会在 Worker 崩溃后主动拉起新实例——这和 Workerman 的 Master/Worker 自愈机制有本质区别。
常见错误现象:frankenphp_worker_restarts_total 指标计数不变;日志里出现 Segmentation fault 或 Fatal error 后,Worker 脚本彻底退出,后续请求全部失败(502 Bad Gateway);ps aux | grep worker.php 查不到对应进程。
- Worker 崩溃后是否恢复,完全取决于你是否在
frankenphp.yaml或 Caddyfile 中配置了restart: always(或restart: on-failure) - 未配置时,FrankenPHP 仅记录错误并停止分发任务,不会尝试重 exec
- 即使配置了
restart: always,重启也非“即时”:有默认 1s 退避,且不保证上下文清理(如 CWD、static 变量仍继承上一次状态) - 若崩溃由 PHP 扩展 segfault 引起,重启可能反复失败,需配合
max_restarts: 3防止雪崩
为什么不能像 Workerman 那样自动守护
FrankenPHP 的 Worker 是通过 exec.Command 启动的独立 PHP CLI 进程,主进程只负责建立 Unix socket 通信通道,并不持有子进程 PID 或注册 SIGCHLD 处理器——它不介入进程生命周期管理,这是设计取舍,不是 bug。
对比 Workerman:pcntl_fork() 创建子进程 + pcntl_waitpid() 监听退出信号,天然支持父子进程强管控;而 FrankenPHP 基于 Go 的 os/exec,默认不保留子进程句柄,也不拦截系统信号。
- Go 标准库的
Cmd.Start()启动后即“放手”,除非你显式调用Cmd.Process.Wait()并做信号处理(FrankenPHP 没这么做) - 这意味着你无法在崩溃瞬间获取 exit code、core dump 路径或触发自定义钩子
- 如果需要类似 Workerman 的强守护,得自己用 systemd 封装 Worker 脚本,或在 Go 层 patch FrankenPHP 源码
如何让 Worker 崩溃后真正恢复
靠 FrankenPHP 自身配置只能做到“有限重启”,要稳定恢复,必须组合三层保障:
- 第一层:Caddyfile 中启用
php { worker ./worker.php; restart always; }(注意语法,不是restart: always) - 第二层:Worker 脚本内避免
exit()、未捕获异常、内存泄漏,加顶层try/catch包裹$worker->wait(),并在 catch 中error_log()后return让进程自然退出,触发重启 - 第三层:用 systemd 管理整个 FrankenPHP 实例,配置
Restart=on-failure和StartLimitIntervalSec=60,防止频繁崩溃拖垮主机
最容易被忽略的是:即使所有配置都开了,Worker 崩溃后重建的进程,其 getcwd() 仍继承前一个实例退出时的路径,static 变量也从上次终止点继续累加——这不是恢复,只是“换了个壳接着跑”。真正的状态隔离,还得靠代码里每次 wait() 前手动重置。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











