Download the PHP package aubes/http-pool-bundle without Composer
On this page you can find all versions of the php package aubes/http-pool-bundle. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download aubes/http-pool-bundle
More information about aubes/http-pool-bundle
Files in aubes/http-pool-bundle
Package http-pool-bundle
Short Description Concurrent HTTP orchestration for Symfony: bounded concurrency, per-host rate limiting, reactive chaining, fire-and-forget.
License MIT
Homepage https://github.com/aubes/http-pool-bundle
Informations about the package http-pool-bundle
aubes/http-pool-bundle
Concurrent HTTP orchestration for Symfony. Fan-out, rate limit, retry, chain: one fluent API, zero stream() boilerplate.
- Bounded concurrency: run up to N requests in parallel, the rest waits in a queue
- Reactive chaining (
then/catch): a response can trigger new requests within the sameflush() - Per-host rate limiting: token bucket throttling per domain (req/s)
- Retry with backoff: configurable per status code, with
Retry-Aftersupport - Fire-and-forget: send requests without waiting, errors are logged silently
- Deduplication (
addOnce): multiple consumers, one HTTP call - Named results: access responses by key via
$results->get('user') - 3 error strategies: collect, stop on first, or throw all
Built on top of HttpClientInterface::stream(), the only non-blocking async primitive in PHP.
Installation
Requirements
- PHP >= 8.3
- Symfony 6.4, 7.4 or 8.0
Why?
Without this bundle, fetching a user and their orders concurrently looks like this:
With http-pool-bundle:
When to use
Use this bundle when you need to call multiple HTTP APIs in a single request/command and want concurrency, rate limiting, retry or reactive chaining without managing stream() manually.
Don't use it for a single HTTP call: HttpClientInterface is perfectly fine on its own.
Quickstart
create() returns a disposable, request-scoped pool. flush() executes all requests (including those added dynamically by callbacks) and returns the results.
Features
Bounded concurrency
The pool keeps at most N requests in flight simultaneously. Excess requests wait in a queue.
Reactive chaining (fan-out)
then() receives the response and the pool. The callback can add new requests that will be processed within the same flush().
Deduplication with addOnce()
addOnce() works like add() but with built-in deduplication. If the key already exists:
- Pending or in flight: returns the existing entry (
then()callbacks accumulate) - Already completed: executes the
then()immediately with the cached response
Only one HTTP request is made, regardless of how many consumers register callbacks.
Works well with Symfony Serializer denormalizers: pass the pool in the denormalization context, and each denormalizer schedules its sub-requests via addOnce().
Fire-and-forget
fire() sends a request without waiting for the response. Errors are logged but do not appear in the results.
Error handling
Global strategies
Three strategies via the ErrorStrategy enum:
| Strategy | flush() returns |
flush() throws |
|---|---|---|
Collect |
PoolResults with getErrors() |
Never |
StopOnFirst |
PoolResults if no errors |
The first error's exception |
ThrowAll |
PoolResults if no errors |
PoolException with all errors |
Per-request catch
catch() handles an error individually. If the callback does not rethrow, the error is considered handled (not counted in getErrors()).
With addOnce(), multiple consumers can each register their own catch(). All are executed independently.
HTTP errors vs callback errors
When a then() callback throws an exception (application bug, parsing error...), it is wrapped in a CallbackException. The original HTTP response remains accessible:
When multiple then() callbacks are registered on the same entry (via addOnce()), each callback runs independently. If the first one fails, the rest still execute.
Retry
Configurable retry per status code with exponential backoff.
Retry is transparent: then() callbacks only run after a successful response. If all attempts fail, the error follows the standard path (catch() or getErrors()).
Retry-After header support (429) is configurable.
Per-host rate limiting
Token bucket per host to respect third-party API limits.
Requests exceeding the limit are delayed automatically. Rate limiting applies between the queue and the concurrency slots.
Configuration
Config values serve as defaults for create(). Each call to create() can override them.
Using a specific HTTP client
By default, the bundle uses the root http_client service. Symfony's scoped clients work transparently: if you configured a scoped client with base_uri: 'https://orders-api.internal', requests matching that host will automatically inherit its options (headers, auth, timeout...).
If you need a pool factory wired to a specific HTTP client (custom transport, dedicated mock, etc.), register your own service with a named alias:
Then inject it:
Profiler
In debug mode, the bundle registers a Web Debug Toolbar panel showing pool activity: request count, fan-out chains, deduplication hits, errors, and flush duration.
License
MIT
All versions of http-pool-bundle with dependencies
psr/log Version ^2.0 | ^3.0
symfony/config Version ^6.4 | ^7.4 | ^8.0
symfony/dependency-injection Version ^6.4 | ^7.4 | ^8.0
symfony/http-client Version ^6.4 | ^7.4 | ^8.0
symfony/http-kernel Version ^6.4 | ^7.4 | ^8.0