跳到主要内容

Async

Async 是 Flight 框架的一个小型包,允许你在 Swoole、AdapterMan、ReactPHP、Amp、RoadRunner、Workerman 等异步服务器和运行时中运行 Flight 应用。开箱即用包含 Swoole 和 AdapterMan 的适配器。

目标:使用 PHP-FPM(或内置服务器)进行开发和调试,在生产环境中以最小改动切换到 Swoole(或其他异步驱动)。

系统要求

  • PHP 7.4 或更高版本
  • Flight 框架 3.16.1 或更高版本
  • Swoole 扩展

安装

通过 composer 安装:

composer require flightphp/async

如果计划使用 Swoole 运行,安装扩展:

# 使用 pecl
pecl install swoole
# 或 openswoole
pecl install openswoole

# 或使用包管理器(Debian/Ubuntu 示例)
sudo apt-get install php-swoole

快速 Swoole 示例

以下是一个最小化设置,展示如何使用同一代码库同时支持 PHP-FPM(或内置服务器)和 Swoole。

项目中需要的文件:

  • index.php
  • swoole_server.php
  • SwooleServerDriver.php

index.php

此文件是一个简单的开关,强制应用在开发中以 PHP 模式运行。

// index.php
<?php

define('NOT_SWOOLE', true);

include 'swoole_server.php';

swoole_server.php

此文件引导你的 Flight 应用,并在未定义 NOT_SWOOLE 时启动 Swoole 驱动。

// swoole_server.php
<?php

require_once __DIR__ . '/vendor/autoload.php';

$app = Flight::app();

$app->route('/', function() use ($app) {
$app->json(['hello' => 'world']);
});

if (!defined('NOT_SWOOLE')) {
// 在 Swoole 模式下运行时引入 SwooleServerDriver 类。
require_once __DIR__ . '/SwooleServerDriver.php';

Swoole\Runtime::enableCoroutine();
$Swoole_Server = new SwooleServerDriver('127.0.0.1', 9501, $app);
$Swoole_Server->start();
} else {
$app->start();
}

SwooleServerDriver.php

一个简洁的驱动,展示如何使用 AsyncBridge 和 Swoole 适配器将 Swoole 请求桥接到 Flight。

// SwooleServerDriver.php
<?php

use flight\adapter\SwooleAsyncRequest;
use flight\adapter\SwooleAsyncResponse;
use flight\AsyncBridge;
use flight\Engine;
use Swoole\HTTP\Server as SwooleServer;
use Swoole\HTTP\Request as SwooleRequest;
use Swoole\HTTP\Response as SwooleResponse;

class SwooleServerDriver {
protected $Swoole;
protected $app;

public function __construct(string $host, int $port, Engine $app) {
$this->Swoole = new SwooleServer($host, $port);
$this->app = $app;

$this->setDefault();
$this->bindWorkerEvents();
$this->bindHttpEvent();
}

protected function setDefault() {
$this->Swoole->set([
'daemonize' => false,
'dispatch_mode' => 1,
'max_request' => 8000,
'open_tcp_nodelay' => true,
'reload_async' => true,
'max_wait_time' => 60,
'enable_reuse_port' => true,
'enable_coroutine' => true,
'http_compression' => false,
'enable_static_handler' => true,
'document_root' => __DIR__,
'static_handler_locations' => ['/css', '/js', '/images', '/.well-known'],
'buffer_output_size' => 4 * 1024 * 1024,
'worker_num' => 4,
]);

$app = $this->app;
$app->map('stop', function (?int $code = null) use ($app) {
if ($code !== null) {
$app->response()->status($code);
}
});
}

protected function bindHttpEvent() {
$app = $this->app;
$AsyncBridge = new AsyncBridge($app);

$this->Swoole->on('Start', function(SwooleServer $server) {
echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$this->Swoole->on('Request', function (SwooleRequest $request, SwooleResponse $response) use ($AsyncBridge) {
$SwooleAsyncRequest = new SwooleAsyncRequest($request);
$SwooleAsyncResponse = new SwooleAsyncResponse($response);

$AsyncBridge->processRequest($SwooleAsyncRequest, $SwooleAsyncResponse);

$response->end();
gc_collect_cycles();
});
}

protected function bindWorkerEvents() {
$createPools = function() {
// 在此创建 worker 特定的连接池
};
$closePools = function() {
// 在此关闭连接池/清理
};
$this->Swoole->on('WorkerStart', $createPools);
$this->Swoole->on('WorkerStop', $closePools);
$this->Swoole->on('WorkerError', $closePools);
}

public function start() {
$this->Swoole->start();
}
}

运行服务器

  • 开发环境(PHP 内置服务器 / PHP-FPM):
    • php -S localhost:8000(如果索引在 public/ 中,则加上 -t public/)
  • 生产环境(Swoole):
    • php swoole_server.php

提示:在生产环境中,在 Swoole 前面使用反向代理 (Nginx) 来处理 TLS、静态文件和负载均衡。

配置说明

Swoole 驱动暴露了几个配置选项:

  • worker_num:worker 进程数
  • max_request:每个 worker 重启前处理的请求数
  • enable_coroutine:使用协程进行并发
  • buffer_output_size:输出缓冲区大小

根据主机资源和流量模式调整这些配置。

错误处理

AsyncBridge 将 Flight 错误转换为适当的 HTTP 响应。你也可以添加路由级错误处理:

$app->route('/*', function() use ($app) {
try {
// 路由逻辑
} catch (Exception $e) {
$app->response()->status(500);
$app->json(['error' => $e->getMessage()]);
}
});

AdapterMan 和其他运行时

AdapterMan 作为替代运行时适配器受支持。该包设计为可适配——添加或使用其他适配器通常遵循相同的模式:通过 AsyncBridge 和运行时特定的适配器将服务器请求/响应转换为 Flight 的请求/响应。