- Do I need to composer require guzzlehttp/promises in a Laravel app?
- Usually not. Laravel's Illuminate\Http\Client is a thin wrapper over Guzzle, and guzzlehttp/guzzle already requires guzzlehttp/promises, so it is present transitively in almost every Laravel install. Require it directly only when you need promise composition such as Utils::all, some, or settle without pulling in the full HTTP client. Running composer require guzzlehttp/promises:^3.0 is typically a no-op on a modern stack.
- Which PHP and Laravel versions does guzzlehttp/promises 3.0 support?
- Version 3.0 requires PHP >=7.4,<8.7. Version 2.5 is in maintenance for PHP >=7.2.5 and 1.5 is end of life for legacy PHP. The package is framework agnostic and has no service provider, config file, or migration, so it works on any Laravel release running a supported PHP version. It behaves identically under PHP-FPM, Octane, and queue workers.
- How do I make parallel HTTP requests in Laravel using async promises?
- Laravel 10+ exposes Http::async(), which returns a GuzzleHttp\Promise\PromiseInterface. Collect the pending promises, then either call Utils::all() or loop over them with wait() to resolve the whole group. Real socket overlap only happens because Guzzle drives the cURL multi handler underneath, so always set explicit timeouts and a per-request concurrency cap. The natural place for this code is the third-party adaptor layer, not controllers or Eloquent models.
- Why does getState() say fulfilled when wait() still throws?
- getState() describes how a promise was settled, not the eventual outcome. If a promise is resolved with another promise, either directly or by returning one from a then handler, it reports fulfilled while the inner promise is still pending, and wait() can throw later if that inner promise rejects. Only poll state on promises settled with plain values, or call wait() first. This is documented in the README and tracked as guzzle/promises issue #101, so branching on getState() is worth flagging in code review.
- Does cancel() actually abort an in-flight HTTP request?
- No. Cancellation is cooperative: cancel() notifies registered handlers and moves the promise state, but it does not abort the underlying cURL transfer or stop the remote vendor's work. Do not treat it as a latency or cost-saving mechanism. Timeouts, concurrency caps, and choosing the right runtime are what actually limit wasted work.
- Can I serialize a promise and dispatch it to a Laravel queue or Horizon?
- No. Promises are in-memory runtime objects and version 3.0 explicitly rejects native serialization of in-flight promises, so one can never cross a queue, cache, or session boundary. Any defer-to-Horizon design must hand off plain parameters and recreate the work inside the job. Design as if the promise cannot outlive the request that created it, because it cannot.
- What is the difference between Utils::all, some, any and settle?
- all() is fail-fast: it rejects as soon as any promise rejects. some($count) resolves once a given number of promises fulfil, any() resolves on the first fulfilment, and settle() always resolves with the per-promise state and value or reason. Use fail-fast when a partial result is useless, and settle or some when you want to degrade gracefully and render whatever succeeded. Decide the partial-failure policy per integration, not globally.
- Does guzzlehttp/promises make my PHP code run in parallel?
- Not by itself. PHP here is cooperative and single-threaded; nothing runs until something calls wait() or drains Utils::queue(). The actual overlap comes from Guzzle's cURL multi handler multiplexing sockets, and this library only provides the composition vocabulary around it. Expect roughly one round trip's worth of concurrency, not background execution after the response is sent.
- Is a blocking wait() safe under Laravel Octane or Swoole?
- It works, but it is a blocking call. Under PHP-FPM it ties up a worker for the duration of the slowest request in the group; under Octane or Swoole it can stall other requests handled by the same worker. Keep waits short, cap fan-out, and prefer coroutine or amphp-based primitives for heavier concurrent workloads. Whatever the runtime, the question to answer up front is whether it tolerates a blocking wait of N seconds.
- Should I type-hint GuzzleHttp\Promise\PromiseInterface in my service classes?
- Prefer keeping PromiseInterface out of domain and service signatures. Wrap the call sites behind a small contract, such as a ParallelRunner interface, inside the adaptor layer that talks to third parties, so the library stays swappable and easy to fake in tests. Decide that boundary once, centrally, rather than letting each feature team choose. It also keeps callers from accidentally branching on getState() or assuming cancel() aborts a socket.