worker模式需同时满足三条件:Caddyfile中站点块内配置worker块、PHP入口显式调用frankenphp_handle_request()、框架原生支持或手动适配常驻生命周期;缺一不可。

worker 模式不是开关一按就生效的附加功能,它需要同时满足三件事:Caddyfile 中启用 worker 块、PHP 入口脚本显式调用 frankenphp_handle_request()、且项目框架本身支持常驻生命周期。缺一不可。
确认你的框架是否真正支持 worker 模式
不是所有“能跑在 FrankenPHP 上”的 PHP 项目都自动适配 worker 模式。关键看它是否已实现对 frankenphp_handle_request() 的封装或兼容。
- Laravel(v10.42+)、Symfony(v6.4+)、Yii3、Laminas 已原生集成,只需改入口文件(如
public/index.php); - ThinkPHP 6 需手动包裹:把原有
(new App())->run()->send()替换为frankenphp_handle_request(new App()); - 纯原生 PHP 或老版本 Laravel/Symfony(< v6.4 / < v10.42)会直接报
Call to undefined function frankenphp_handle_request(),必须升级或自行补全启动逻辑; - 不改入口、只配 Caddyfile 是无效的——FrankenPHP 不会自动重写请求入口。
worker 块必须放在站点配置内,不能只写在全局块中
常见错误是把 worker 写在 { } 全局选项里,比如:
{
worker {
file ./worker.php
}
}这不会生效。FrankenPHP 要求 worker 必须嵌套在某个具体站点块中,例如:
立即学习“PHP免费学习笔记(深入)”;
localhost {
root * ./public
php_server
worker {
file ./worker.php
num 4
env APP_ENV production
}
}-
file必须是绝对路径或相对于当前 Caddyfile 的路径,且该文件需存在、可执行; -
num默认为 CPU 核心数 × 2,但生产环境建议设为 2–4,避免线程争抢; - 若使用
import引入子配置(如import Caddyfile.d/*.caddyfile),worker块也必须出现在被导入的文件中,且位于站点块内部。
入口脚本必须显式调用 frankenphp_handle_request()
这是最常被跳过的一步。即使 Caddyfile 和框架都 OK,没改 public/index.php 就等于没开 worker。
以 Laravel 为例,原始入口类似:
<?php require_once __DIR__.'/../vendor/autoload.php'; $app = require_once __DIR__.'/../bootstrap/app.php'; $kernel = $app->make(Illuminate\Contracts\Http\Kernel::class); $response = $kernel->handle($request = Illuminate\Http\Request::capture()); $response->send(); $kernel->terminate($request, $response);
要改为:
<?php require_once __DIR__.'/../vendor/autoload.php'; $app = require_once __DIR__.'/../bootstrap/app.php'; frankenphp_handle_request($app);
-
frankenphp_handle_request()接收一个可调用对象(通常是框架 Application 实例),内部会接管请求循环、复用容器和服务; - 不能再有
$response->send()或$kernel->terminate()—— 这些由 FrankenPHP 在每次请求结束后自动处理; - 如果入口中还包含
exit、die或未捕获异常退出,会导致 worker 进程崩溃并触发max_consecutive_failures重启机制。
调试时别忽略 max_consecutive_failures 和日志路径
worker 启动失败往往静默退出,只留一行 “worker exited” 在日志里。根本原因常藏在 PHP 错误中,但默认不输出到控制台。
- 加
env APP_DEBUG true到worker块,强制暴露错误; - 设置
max_consecutive_failures -1可防止反复崩溃后被永久停用(仅限调试); - 日志默认走 Caddy 的
log指令,若没配,就去stderr;推荐显式加:log { output file /var/log/frankenphp-worker.log } - 注意:worker 模式下,
php_ini display_errors=On无效,错误必须通过日志或error_log()输出。
FrankenPHP 的 worker 模式本质是让 PHP 应用进程常驻,但它不会帮你绕过框架本身的生命周期契约。入口函数怎么写、服务怎么注册、异常怎么兜底——这些仍由你负责。配置只是引子,真正的“常驻”发生在你把初始化逻辑从请求中剥离出来的那一刻。



















