PHPackages                             fansipan/peak - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [HTTP &amp; Networking](/categories/http)
4. /
5. fansipan/peak

ActiveLibrary[HTTP &amp; Networking](/categories/http)

fansipan/peak
=============

A simple and efficient solution for concurrently sending HTTP requests using PSR-18 client implementations.

0.1.0(2y ago)76MITPHPPHP ^8.1

Since Jul 12Pushed 2y ago1 watchersCompare

[ Source](https://github.com/phanxipang/peak)[ Packagist](https://packagist.org/packages/fansipan/peak)[ Docs](https://github.com/phanxipang/peak)[ RSS](/packages/fansipan-peak/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (15)Versions (3)Used By (0)

Peak
====

[](#peak)

[![Latest Version on Packagist](https://camo.githubusercontent.com/546b3bb1ff2c0aaacb5d919ce7204d5e40b0d24a61b3bc38feaae919fa791881/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f66616e736970616e2f7065616b2e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/fansipan/peak)[![Github Actions](https://camo.githubusercontent.com/47fbb40aa82d5da0ebee2bdb11fb5a7d493bfbacb8bceeee3c2ded3c4161bcaf/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7068616e786970616e672f7065616b2f74657374696e672e796d6c3f6272616e63683d6d61696e266c6162656c3d616374696f6e73266c6f676f3d676974687562267374796c653d666f722d7468652d6261646765)](https://github.com/phanxipang/peak)[![Codecov](https://camo.githubusercontent.com/c310b2e3145767d3c87e7626b57a3490cd4ddaf89965d6689dd333a66ab54c85/68747470733a2f2f696d672e736869656c64732e696f2f636f6465636f762f632f6769746875622f7068616e786970616e672f7065616b3f6c6f676f3d636f6465636f76267374796c653d666f722d7468652d6261646765)](https://codecov.io/gh/phanxipang/peak)[![Total Downloads](https://camo.githubusercontent.com/2b668aba8bb5dac09cb9d2533f6ed64a58c49c38bbaf48a910a4018b29cc0fd5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f66616e736970616e2f7065616b2e7376673f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/fansipan/peak)[![Software License](https://camo.githubusercontent.com/9897f4467850972a38c7db9a4d38280b8fcdac0ada00e9c8c0a72ecfa8551653/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666f722d7468652d6261646765)](LICENSE.md)

A simple and efficient solution for concurrently sending HTTP requests using PSR-18 client implementations.

Peak is a library that enables concurrent request sending using a request pool. It leverages the event loop of [AMPHP](https://github.com/amphp), [ReactPHP](https://github.com/reactphp) or [PSL](https://github.com/azjezz/psl) to handle and manage the requests concurrently.

Requirements
------------

[](#requirements)

- PHP 8.1 or higher.
- A package that supports non-block I/O using Fibers under the hood (now refer as **driver**).

Installation
------------

[](#installation)

You can install the package via composer:

```
composer require fansipan/peak
```

Additionally, depending on your choice of driver, these packages may also need to be installed.

### AMPHP

[](#amphp)

```
composer require amphp/pipeline
```

### PSL

[](#psl)

```
composer require azjezz/psl
```

### ReactPHP

[](#reactphp)

```
composer require clue/mq-react react/async
```

Usage
-----

[](#usage)

### Create Request Pool

[](#create-request-pool)

Typical applications would use the `PoolFactory` class to create a pool.

```
use Fansipan\Peak\PoolFactory;

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

It will attempt to create async version of the client using `AsyncClientFactory`. The supported clients are [Guzzle](https://github.com/guzzle/guzzle) and [Symfony HTTPClient](https://github.com/symfony/http-client) ([`Psr18Client`](https://symfony.com/doc/current/http_client.html#psr-18-and-psr-17)).

> You can use any PSR-18 client implementations with ReactPHP driver. If an unsupported client is used, it will be replaced with the [`Browser`](https://github.com/reactphp/http#browser) HTTP client (require `react/http` installed).

The `Fansipan\Peak\PoolFactory` provides a configured request pool based on the installed packages, which is suitable for most cases. However, if desired, you can specify a particular implementation if it is available on your platform and/or in your application.

First, you need to create your desired driver:

```
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();
```

Then create an asynchronous client, which is essentially a decorator for the PSR-18 client:

```
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);
```

### Sending Requests

[](#sending-requests)

The `send` method accepts an iterator of PSR-7 requests or closures/invokable class which receive an `Psr\Http\Client\ClientInterface` instance.

```
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));
```

### Retrieving Responses

[](#retrieving-responses)

As you can see from the example above, each response instance can be accessed using an index. However, the response order is not guaranteed. If you wish, you can assign names to the requests to easily track the specific requests that have been sent. This allows you to access the corresponding responses by their assigned names.

```
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']);
```

### Concurrency Limit

[](#concurrency-limit)

Sending an excessive number of requests may either take up all resources on your side or it may even get you banned by the remote side if it sees an unreasonable number of requests from your side.

As a consequence, it's usually recommended to limit concurrency on the sending side to a reasonable value. It's common to use a rather small limit, as doing more than a dozen of things at once may easily overwhelm the receiving side.

You can use `concurrent` method to set the maximum number of requests to send concurrently. The default value is `25`.

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

Additional requests that exceed the concurrency limit will automatically be enqueued until one of the pending requests completes.

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) and [CODE\_OF\_CONDUCT](CODE_OF_CONDUCT.md) for details.

Security
--------

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Lynh](https://github.com/jenky)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

22

—

LowBetter than 22% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity9

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

923d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/783e915bb411d566e8f1035f197842db5e870a2a995b3943bcbe5db2f9abf09b?d=identicon)[Milano](/maintainers/Milano)

---

Top Contributors

[![jenky](https://avatars.githubusercontent.com/u/1808758?v=4)](https://github.com/jenky "jenky (51 commits)")

---

Tags

asyncconcurrenthttpparralelpsr-18httpresponserequestasyncpoolawaitconcurrentlyconcurrent-requestsparallel-requests

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/fansipan-peak/health.svg)

```
[![Health](https://phpackages.com/badges/fansipan-peak/health.svg)](https://phpackages.com/packages/fansipan-peak)
```

###  Alternatives

[guzzlehttp/psr7

PSR-7 message implementation that also provides common utility methods

8.0k1.0B3.2k](/packages/guzzlehttp-psr7)[art4/requests-psr18-adapter

Use WordPress/Requests as a PSR-18 HTTP client

153.3k](/packages/art4-requests-psr18-adapter)[sunrise/http-message

An HTTP message implementation based on PSR-7, PSR-17 and RFC-7230.

15112.3k15](/packages/sunrise-http-message)[chillerlan/php-httpinterface

A PSR-7/17/18 http message/client implementation

1417.1k5](/packages/chillerlan-php-httpinterface)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
