FrankenPHP常驻运行需满足三要素:进程长期存在、初始化耗时稳定在个位数毫秒、全局状态跨请求复用;需确认worker模式启用、Caddyfile配置正确、入口文件调用frankenphp_handle_request()。

看进程是否长期存在,而非临时拉起
FrankenPHP 的“常驻”本质是进程不随请求结束而退出。如果每次请求后 frankenphp 进程就消失,说明没跑在 worker 模式,或者根本没启动成功。
执行 ps aux | grep frankenphp,正常应看到持续存在的主进程(如 frankenphp run)和若干 frankenphp-worker 子进程(worker 模式下)。若只看到一闪而过的进程,或只有 php artisan serve 类似行为,那只是普通 CLI 模式,不是常驻。
- worker 模式下,
frankenphp-worker进程数应稳定(由workers.count控制),不会随并发请求飙升 - 用
watch -n 1 'ps aux | grep frankenphp | wc -l'观察 10 秒内进程数是否跳变——跳变说明进程频繁启停,非常驻 - Docker 环境下,
docker ps显示容器状态为Up X minutes且无重启计数,是基础佐证
查日志里有没有 “Application initialized in Xms” 的稳定低耗时
Laravel/Symfony/ThinkPHP 等框架在请求日志中会打一条 Application initialized in ...ms。常驻运行的核心标志是这个耗时不再波动,而是稳定在个位数毫秒(如 3ms 或 7ms),且连续 100+ 请求都如此。
如果该数字仍像 PHP-FPM 那样每请求都在 50–120ms 波动,说明框架仍在重复加载,FrankenPHP 并未真正接管生命周期。
立即学习“PHP免费学习笔记(深入)”;
- 确保日志级别为
debug(如 Laravel 的LOG_LEVEL=debug) - 不要只看第一条日志——首次请求可能略高,采样至少 50 个请求再判断趋势
- 若用自定义入口(如 ThinkPHP 的
worker.php),需确认其中调用了frankenphp_handle_request()而非$app->run()
验证 $_SERVER 和单例对象是否跨请求复用
常驻模式下,PHP 进程不销毁,全局变量、静态属性、服务容器实例都应保留。这是最容易被忽略也最易出错的验证点。
写一个测试脚本(如 /test-state.php):
<?php
static $counter = 0;
$counter++;
echo "Counter: $counter\n";
echo "Time: " . date('H:i:s') . "\n";
echo "PID: " . getmypid() . "\n";
?>反复 curl 它(curl http://localhost/test-state.php),观察输出:
-
Counter是否递增(如 1→2→3…)?递增说明静态变量跨请求存活 -
PID是否始终不变?不变说明是同一个 PHP 进程在处理 -
Time是否连续更新?说明不是冷启动重载脚本 - 若 Counter 始终为 1,或 PID 频繁变化,说明常驻未生效,可能误用了
php-server模式或 Caddyfile 配置漏了worker块
检查 Caddyfile 是否启用 worker 且路径正确
FrankenPHP 的常驻能力必须显式开启。仅靠 frankenphp run 默认是普通 HTTP 模式,不常驻;worker 模式依赖 Caddyfile 中的 worker 块和正确的入口文件路径。
典型正确配置片段:
localhost {
root * /var/www/myapp/public
php_backend
worker {
file "public/worker.php"
}
}-
worker必须是独立块,不能嵌套在route或php内 -
file指向的路径必须存在,且该文件必须包含frankenphp_handle_request()调用 - 若项目是 Laravel,
public/worker.php应由php artisan octane:frankenphp生成,不能手写或复用index.php - 配置改完后必须重启 FrankenPHP(
kill -SIGTERM当前进程再重新frankenphp run),热重载不生效
真正的常驻不是“看起来没退出”,而是进程稳、初始化快、状态可延续——三者缺一不可。最容易卡在 worker 配置遗漏或入口脚本不兼容上,建议先用官方模板生成 worker.php,再逐步替换逻辑。



















