fansipan/peak

使用 PSR-18 客户端实现并发发送 HTTP 请求的简单高效解决方案。

0.1.0 2023-11-05 13:13 UTC

This package is auto-updated.

Last update: 2024-09-05 15:04:35 UTC


README

Latest Version on Packagist Github Actions Codecov Total Downloads Software License

使用 PSR-18 客户端实现并发发送 HTTP 请求的简单高效解决方案。

Peak 是一个库,它通过请求池实现并发请求发送。它利用 AMPHPC、ReactPHP 或 PSL 的事件循环来并发处理和管理工作请求。

要求

  • PHP 8.1 或更高版本。
  • 一个支持底层使用 Fibers 进行非阻塞 I/O 的包(现在称为 驱动器)。

安装

您可以通过 composer 安装此包。

composer require fansipan/peak

此外,根据您的驱动器选择,可能还需要安装以下包。

AMPHPC

composer require amphp/pipeline

PSL

composer require azjezz/psl

ReactPHP

composer require clue/mq-react react/async

使用

创建请求池

典型应用程序会使用 PoolFactory 类来创建一个池。

use Fansipan\Peak\PoolFactory;

/** @var \Psr\Http\Client\ClientInterface $client */
$pool = PoolFactory::createForClient($client);

它将尝试使用 AsyncClientFactory 创建客户端的异步版本。支持的客户端包括 GuzzleSymfony HTTPClient (Psr18Client)。

您可以使用任何与 ReactPHP 驱动器兼容的 PSR-18 客户端实现。如果使用不支持的客户端,它将被替换为 Browser HTTP 客户端(需要安装 react/http)。

Fansipan\Peak\PoolFactory 提供了一个基于已安装包的配置请求池,这对于大多数情况都是合适的。但是,如果您希望,您也可以指定特定的实现,如果它在您的平台和/或应用程序中可用。

首先,您需要创建所需的驱动器

use Fansipan\Peak\Concurrency\AmpDeferred;
use Fansipan\Peak\Concurrency\PslDeferred;
use Fansipan\Peak\Concurrency\ReactDeferred;

// AMPHP
$defer = new AmpDeferred();

// PSL
$defer = new PslDeferred();

// ReactPHP
$defer = new ReactDeferred();

然后创建一个异步客户端,它实际上是 PSR-18 客户端的装饰器

use Fansipan\Peak\Client\GuzzleClient;
use Fansipan\Peak\Client\SymfonyClient;
use Fansipan\Peak\ClientPool;

// Guzzle

$asyncClient = new GuzzleClient($defer);
// or using existing Guzzle client
/** @var \GuzzleHttp\ClientInterface $client */
$asyncClient = new GuzzleClient($defer, $client);

// Symfony HTTP Client

$asyncClient = new SymfonyClient($defer);
// or using existing Symfony client
/** @var \Symfony\Contracts\HttpClient\HttpClientInterface $client */
$asyncClient = new SymfonyClient($defer, $client);


$pool = new ClientPool($asyncClient);

发送请求

send 方法接受一个 PSR-7 请求的迭代器或接受 Psr\Http\Client\ClientInterface 实例的闭包/可调用类。

use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

// Using array
$responses = $pool->send([
    $psr7Request,
    fn (ClientInterface $client): ResponseInterface => $client->sendRequest($psr7Request),
]);

var_dump($responses[0]);
var_dump($responses[1]);

// Using generator when you have an indeterminate amount of requests you wish to send
$requests = static function (int $total) {
    for ($i = 0; $i < $total; $i++) {
        yield $psr7Request;
    }
}
$responses = $pool->send($requests(100));

获取响应

如您从上面的示例中看到,每个响应实例都可以通过索引访问。但是,响应顺序没有保证。如果您愿意,您可以为请求分配名称,以便轻松跟踪已发送的特定请求。这允许您通过其分配的名称访问相应的响应。

use Psr\Http\Client\ClientInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;

$responses = $pool->send([
    'first' => $psr7Request,
    'second' => fn (ClientInterface $client): ResponseInterface => $client->sendRequest($psr7Request),
]);

// Or using generator

$requests = function (): \Generator {
    yield 'first' => $psr7Request;
    yield 'second' => fn (ClientInterface $client): ResponseInterface => $client->sendRequest($psr7Request);
};

$responses = $pool->send($requests());

var_dump($responses['first']);
var_dump($responses['second']);

并发限制

发送过多的请求可能会占用您这边的所有资源,或者如果远程端看到来自您这边的请求数量不合理,甚至可能会被禁用。

因此,通常建议将发送侧的并发限制在合理的值。通常使用相当小的限制,因为一次做超过十几件事可能会很容易压倒接收方。

您可以使用 concurrent 方法设置并发发送的最大请求数。默认值为 25

$response = $pool
    ->concurrent(10) // Process up to 10 requests concurrently
    ->send($requests);

超过并发限制的额外请求将自动入队,直到其中一个待处理请求完成。

测试

composer test

更新日志

请参阅 CHANGELOG 了解最近发生了什么更改。

贡献

请参阅 CONTRIBUTINGCODE_OF_CONDUCT 以获取详细信息。

安全性

如果您发现任何安全相关的问题,请发送电子邮件至 contact@lynh.me,而不是使用问题跟踪器。

致谢

许可证

MIT 许可证 (MIT)。请参阅 许可证文件 以获取更多信息。