frankenphp 本身无自愈能力,异常退出后能否自动恢复取决于启动机制:linux 用 systemd(配 restart=always、restartsec=5 等)可实现进程级自动拉起;windows 需在 sc 注册服务后手动配置“恢复”策略;docker 则依赖 restart policy 与 healthcheck 协同触发真实恢复。

FrankenPHP 本身不提供进程自愈能力,服务异常退出后能否自动恢复,完全取决于你用什么机制启动它——systemd、Windows Service 还是 Docker,决定了 recovery 的粒度和可靠性。
Linux 下用 systemd 确保 worker 崩溃后自动拉起
systemd 是目前最可控、最稳定的恢复方案。关键不是“重启 FrankenPHP”,而是让 systemd 持续盯住它的主进程,并在退出时按策略重建。
-
Type=simple配合Restart=always:适用于 FrankenPHP 直接运行(如frankenphp run),只要进程退出就立即重启 -
RestartSec=5必须设置:避免进程反复崩溃导致系统高频重试,也给日志落盘留出时间 -
StartLimitIntervalSec=60和StartLimitBurst=3要配对加:防止 1 分钟内连续崩 3 次后被 systemd 拉黑(默认行为) - 别漏掉
Environment=FRANKENPHP_DEBUG=1:worker 崩溃时能多输出一条X-PHP-Exception头,方便前端或监控快速识别 - 检查
journalctl -u frankenphp -n 100:崩溃日志通常出现在 service 启动失败的前几行,不是最后几行
Windows 上靠 sc + 服务恢复策略兜底
sc 注册的服务默认不具备智能恢复逻辑,必须手动配置“失败时重新启动”选项,否则进程一崩就静默停摆。
- 注册完服务后,进
services.msc找到FrankenPHP→ 右键 → “属性” → “恢复” 页签 - 第一、二、三次失败都选“重新启动服务”,延迟设为 30 秒(避免和 Windows 自身服务冲突)
- “重置失败计数”设为 1 天,防止某天集中出错后长期锁死
- 务必确认
binPath中路径不含空格或中文;若含,整个值要用英文双引号包裹,且sc create命令中binPath=后必须有空格 - 启动失败时别只看
sc query,要查“事件查看器 → Windows 日志 → 系统”,错误事件 ID 通常是 7000 或 7009
Docker 环境下靠 restart policy + healthcheck 协同判断
单纯 restart: always 不够——容器可能卡在健康但无响应的状态。需要 healthcheck 主动探测 HTTP 端点,才能触发真实恢复。
-
restart: unless-stopped比always更稳妥:避免人为docker stop后又被拉起 - 必须加
healthcheck,例如:curl -f http://localhost:8000/health || exit 1,间隔设为 10s,超时 5s,失败 3 次即标记 unhealthy - FrankenPHP 容器内需暴露健康接口,比如在
Caddyfile里加路由:handle /health { respond "OK" 200 } - 别依赖
depends_on.healthcheck:Docker Compose 的 depends_on 不等 healthcheck 就启动依赖服务,容易导致上游调用失败 - 日志要定向到 stdout:
ExecStart=/usr/local/bin/frankenphp run --config /app/Caddyfile --log stdout,否则docker logs看不到崩溃线索
为什么 set_exception_handler() 不能替代进程级恢复
很多人试图在 PHP 入口里用 set_exception_handler() 捕获所有异常来“防崩”,这在 worker 模式下是无效的——handler 只作用于单次请求,无法阻止 frankenphp_handle_request() 外部的致命错误(如 OPcache 编译失败、扩展初始化段错误、require 路径错误)直接杀死整个 worker 进程。
- 真正要拦截的,是
frankenphp_handle_request()回调函数外层的try/catch,它能兜住未被捕获的Fatal error和Parse error(前提是没触发 Zend 引擎级崩溃) - 但
Segmentation fault、Bus error、Out of memory这类信号级崩溃,PHP 层根本捕获不到,只能靠 systemd/sc/Docker 这类宿主机制回收进程 - 如果你发现
journalctl或docker logs里只有 “Process exited with status 139”,那基本就是 segfault,得查扩展兼容性或 Go runtime 冲突,不是 PHP 代码能修的
真正决定恢复成败的,从来不是 FrankenPHP 自己有多“健壮”,而是你有没有把它放进一个能感知退出、能重试、能记录上下文的托管环境里。任何脱离宿主机制谈“自愈”的方案,上线后都会在凌晨三点给你发消息。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











