Sending Requests With a Pool

You can send requests concurrently using a fixed size pool via the GuzzleHttp\Pool class. The Pool class is an implementation of GuzzleHttp\Ring\Future\FutureInterface, meaning it can be dereferenced at a later time or cancelled before sending. The Pool constructor accepts a client object, iterator or array that yields GuzzleHttp\Message\RequestInterface objects, and an optional associative array of options that can be used to affect the transfer.

  1. use GuzzleHttp\Pool;
  2. $requests = [
  3. $client->createRequest('GET', 'http://httpbin.org'),
  4. $client->createRequest('DELETE', 'http://httpbin.org/delete'),
  5. $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'test'])
  6. ];
  7. $options = [];
  8. // Create a pool. Note: the options array is optional.
  9. $pool = new Pool($client, $requests, $options);
  10. // Send the requests
  11. $pool->wait();

The Pool constructor accepts the following associative array of options:

  • pool_size: Integer representing the maximum number of requests that are allowed to be sent concurrently.
  • before: Callable or array representing the event listeners to add to each request’s before event.
  • complete: Callable or array representing the event listeners to add to each request’s complete event.
  • error: Callable or array representing the event listeners to add to each request’s error event.
  • end: Callable or array representing the event listeners to add to each request’s end event.

The “before”, “complete”, “error”, and “end” event options accept a callable or an array of associative arrays where each associative array contains a “fn” key with a callable value, an optional “priority” key representing the event priority (with a default value of 0), and an optional “once” key that can be set to true so that the event listener will be removed from the request after it is first triggered.

  1. use GuzzleHttp\Pool;
  2. use GuzzleHttp\Event\CompleteEvent;
  3. // Add a single event listener using a callable.
  4. Pool::send($client, $requests, [
  5. 'complete' => function (CompleteEvent $event) {
  6. echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n";
  7. echo 'Response: ' . $event->getResponse()->getBody() . "\n\n";
  8. }
  9. ]);
  10. // The above is equivalent to the following, but the following structure
  11. // allows you to add multiple event listeners to the same event name.
  12. Pool::send($client, $requests, [
  13. 'complete' => [
  14. [
  15. 'fn' => function (CompleteEvent $event) { /* ... */ },
  16. 'priority' => 0, // Optional
  17. 'once' => false // Optional
  18. ]
  19. ]
  20. ]);

Asynchronous Response Handling

When sending requests concurrently using a pool, the request/response/error lifecycle must be handled asynchronously. This means that you give the Pool multiple requests and handle the response or errors that is associated with the request using event callbacks.

  1. use GuzzleHttp\Pool;
  2. use GuzzleHttp\Event\ErrorEvent;
  3. Pool::send($client, $requests, [
  4. 'complete' => function (CompleteEvent $event) {
  5. echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n";
  6. echo 'Response: ' . $event->getResponse()->getBody() . "\n\n";
  7. // Do something with the completion of the request...
  8. },
  9. 'error' => function (ErrorEvent $event) {
  10. echo 'Request failed: ' . $event->getRequest()->getUrl() . "\n";
  11. echo $event->getException();
  12. // Do something to handle the error...
  13. }
  14. ]);

The GuzzleHttp\Event\ErrorEvent event object is emitted when an error occurs during a transfer. With this event, you have access to the request that was sent, the response that was received (if one was received), access to transfer statistics, and the ability to intercept the exception with a different GuzzleHttp\Message\ResponseInterface object. See Event System for more information.

Handling Errors After Transferring

It sometimes might be easier to handle all of the errors that occurred during a transfer after all of the requests have been sent. Here we are adding each failed request to an array that we can use to process errors later.

  1. use GuzzleHttp\Pool;
  2. use GuzzleHttp\Event\ErrorEvent;
  3. $errors = [];
  4. Pool::send($client, $requests, [
  5. 'error' => function (ErrorEvent $event) use (&$errors) {
  6. $errors[] = $event;
  7. }
  8. ]);
  9. foreach ($errors as $error) {
  10. // Handle the error...
  11. }

Batching Requests

Sometimes you just want to send a few requests concurrently and then process the results all at once after they’ve been sent. Guzzle provides a convenience function GuzzleHttp\Pool::batch() that makes this very simple:

  1. use GuzzleHttp\Pool;
  2. use GuzzleHttp\Client;
  3. $client = new Client();
  4. $requests = [
  5. $client->createRequest('GET', 'http://httpbin.org/get'),
  6. $client->createRequest('HEAD', 'http://httpbin.org/get'),
  7. $client->createRequest('PUT', 'http://httpbin.org/put'),
  8. ];
  9. // Results is a GuzzleHttp\BatchResults object.
  10. $results = Pool::batch($client, $requests);
  11. // Can be accessed by index.
  12. echo $results[0]->getStatusCode();
  13. // Can be accessed by request.
  14. echo $results->getResult($requests[0])->getStatusCode();
  15. // Retrieve all successful responses
  16. foreach ($results->getSuccessful() as $response) {
  17. echo $response->getStatusCode() . "\n";
  18. }
  19. // Retrieve all failures.
  20. foreach ($results->getFailures() as $requestException) {
  21. echo $requestException->getMessage() . "\n";
  22. }

GuzzleHttp\Pool::batch() accepts an optional associative array of options in the third argument that allows you to specify the ‘before’, ‘complete’, ‘error’, and ‘end’ events as well as specify the maximum number of requests to send concurrently using the ‘pool_size’ option key.