该页面已由社区翻译,可能不是最新的。参见参考版本(英文)。

该页面已由社区翻译,可能不是最新的。参见参考版本(英文)。

该页面已由社区翻译,可能不是最新的。参见参考版本(英文)。

由...提供支持
使用 FrankenPHP Workers

使用 FrankenPHP Workers

启动一次应用程序并将其保存在内存中。 FrankenPHP 将在几毫秒内处理传入请求。

# 启动 Worker 脚本

# Docker

FRANKENPHP_CONFIG 环境变量的值设置为 worker /path/to/your/worker/script.php

docker run \
    -e FRANKENPHP_CONFIG="worker /app/path/to/your/worker/script.php" \
    -v $PWD:/app \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

# 独立二进制文件

使用 php-server 命令的 --worker 选项通过 worker 为当前目录的内容提供服务:

frankenphp php-server --worker /path/to/your/worker/script.php

如果你的 PHP 应用程序已嵌入到二进制文件中,你可以在应用程序的根目录中添加自定义的 Caddyfile。 它将被自动使用。

还可以使用 --watch 选项在文件更改时重启 worker。 如果 /path/to/your/app/ 目录或子目录中任何以 .php 结尾的文件被修改,以下命令将触发重启:

frankenphp php-server --worker /path/to/your/worker/script.php --watch="/path/to/your/app/**/*.php"

# Symfony Runtime

FrankenPHP 的 worker 模式由 Symfony Runtime Component 支持。 要在 worker 中启动任何 Symfony 应用程序,请安装 PHP Runtime 的 FrankenPHP 包:

composer require runtime/frankenphp-symfony

通过定义 APP_RUNTIME 环境变量来使用 FrankenPHP Symfony Runtime 启动你的应用服务器:

docker run \
    -e FRANKENPHP_CONFIG="worker ./public/index.php" \
    -e APP_RUNTIME=Runtime\\FrankenPhpSymfony\\Runtime \
    -v $PWD:/app \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

# Laravel Octane

请参阅专门的文档

# 自定义应用程序

以下示例展示了如何创建自己的 worker 脚本而不依赖第三方库:

<?php
// public/index.php

// 防止客户端连接中断时 worker 脚本终止
ignore_user_abort(true);

// 启动你的应用程序
require __DIR__.'/vendor/autoload.php';

$myApp = new \App\Kernel();
$myApp->boot();

// 在循环外的处理器以获得更好的性能(减少工作量)
$handler = static function () use ($myApp) {
    // 当收到请求时调用,
    // 超全局变量、php://input 等都会被重置
    echo $myApp->handle($_GET, $_POST, $_COOKIE, $_FILES, $_SERVER);
};

$maxRequests = (int)($_SERVER['MAX_REQUESTS'] ?? 0);
for ($nbRequests = 0; !$maxRequests || $nbRequests < $maxRequests; ++$nbRequests) {
    $keepRunning = \frankenphp_handle_request($handler);

    // 在发送 HTTP 响应后做一些事情
    $myApp->terminate();

    // 调用垃圾收集器以减少在页面生成过程中触发垃圾收集的可能性
    gc_collect_cycles();

    if (!$keepRunning) break;
}

// 清理
$myApp->shutdown();

然后,启动你的应用程序并使用 FRANKENPHP_CONFIG 环境变量配置你的 worker:

docker run \
    -e FRANKENPHP_CONFIG="worker ./public/index.php" \
    -v $PWD:/app \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

默认情况下,每个 CPU 启动 2 个 worker。 你也可以配置要启动的 worker 数量:

docker run \
    -e FRANKENPHP_CONFIG="worker ./public/index.php 42" \
    -v $PWD:/app \
    -p 80:80 -p 443:443 -p 443:443/udp \
    dunglas/frankenphp

# 在处理一定数量的请求后重启 Worker

由于 PHP 最初不是为长时间运行的进程而设计的,仍有许多库和传统代码会泄漏内存。 在 worker 模式下使用此类代码的一个解决方法是在处理一定数量的请求后重启 worker 脚本:

前面的 worker 代码片段允许通过设置名为 MAX_REQUESTS 的环境变量来配置要处理的最大请求数。

# 手动重启 Workers

虽然可以在文件更改时重启 workers,但也可以通过 Caddy admin API 优雅地重启所有 workers。如果在你的 Caddyfile 中启用了 admin,你可以通过简单的 POST 请求 ping 重启端点,如下所示:

curl -X POST http://localhost:2019/frankenphp/workers/restart

# Worker 故障

如果 worker 脚本因非零退出代码而崩溃,FrankenPHP 将使用指数退避策略重启它。 如果 worker 脚本保持运行的时间超过上次退避 × 2, 它将不会惩罚 worker 脚本并再次重启它。 但是,如果 worker 脚本在短时间内继续以非零退出代码失败 (例如,脚本中有拼写错误),FrankenPHP 将崩溃并出现错误:too many consecutive failures

可以在你的 Caddyfile 中使用 max_consecutive_failures 选项配置连续失败的次数:

frankenphp {
    worker {
        # ...
        max_consecutive_failures 10
    }
}

# 超全局变量行为

PHP 超全局变量$_SERVER$_ENV$_GET…) 行为如下:

  • 在第一次调用 frankenphp_handle_request() 之前,超全局变量包含绑定到 worker 脚本本身的值
  • 在调用 frankenphp_handle_request() 期间和之后,超全局变量包含从处理的 HTTP 请求生成的值,每次调用 frankenphp_handle_request() 都会更改超全局变量的值

要在回调内访问 worker 脚本的超全局变量,必须复制它们并将副本导入到回调的作用域中:

<?php
// 在第一次调用 frankenphp_handle_request() 之前复制 worker 的 $_SERVER 超全局变量
$workerServer = $_SERVER;

$handler = static function () use ($workerServer) {
    var_dump($_SERVER); // 与请求绑定的 $_SERVER
    var_dump($workerServer); // worker 脚本的 $_SERVER
};

// ...
编辑此页面