Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the correct way to use Guzzle 6 to create pool of asynchronous json requests to send to API endpoints?

My objective is to use Guzzle 6 to create a pool of asynchronous requests that PUT json data. Then monitor each $promise success/failure.

For comparison to my POOL code example, the following single request to $client->request() converts the 3rd parameter to encoded json and then adds the Content-type:application/json.**

$client = new Client([
    'base_uri' => BASE_URL . 'test/async/', // Base URI is used with relative requests
    'timeout'  => 0, // 0 no timeout for operations and watching Promises
]);

$response = $client->request('PUT', 'cool', ['json' => ['foo' => 'bar']]);

On the receiving API endpoint, I can read the json from the single request above by doing the following:

$json = file_get_contents('php://input');
$json = json_decode($json, true);

Using the concurrent requests example in the docs, for creating a Pool of asynchronous requests using new Request(), I hoped the same parameters (method, url endpoint, json flag) could be used, as in the single $client->request() example above. However, yield new Request() does not handle the 3rd json parameter like $client->request(). What is the correct Guzzle function to call from my Pool code to set json and content-type correctly? Or is there a better way to create a large pool of asynchronous requests and monitor their outcome?

POOL code example:

$this->asyncRequests = [
    [
        'endpoint' => 'cool'
    ],
    [
        'endpoint' => 'awesome'
    ],
    [
        'endpoint' => 'crazy'
    ],
    [
        'endpoint' => 'weird'
    ]
];

$client = new Client([
    'base_uri' => BASE_URL, // Base URI is used with relative requests
    'timeout'  => 0 // 0 no timeout for operations and watching Promises
]);

$requests = function ($asyncRequests) {
    $uri = BASE_URL . 'test/async/';

    foreach ($asyncRequests as $key => $data) {
        yield new Request('PUT', "{$uri}{$data['endpoint']}", ['json' => ['foo' => 'bar']]);
    }
};

$pool = new Pool($client, $requests($this->asyncRequests), [
    'concurrency' => 10,
    'fulfilled' => function ($response, $index) {
        $this->handleSuccessPromises($response, $index);
    },
    'rejected' => function ($reason, $index) {
        $this->handleFailurePromises($reason, $index);
    },
]);

$promise = $pool->promise(); // Initiate the transfers and create a promise

$promise->wait(); // Force the pool of requests to complete.
like image 337
Zelf Avatar asked Apr 07 '16 20:04

Zelf


2 Answers

Hopefully, someone else will jump in and let me know if there is a more correct way to accomplish my objective, but after looking under the hood in Guzzle I realized new Request()'s 3rd parameter was looking for header information, and the 4th parameter was looking for a body. So the following code works using the Pool.:

foreach ($syncRequests as $key => $headers) {
    yield new Request('PUT', "{$uri}{$headers['endpoint']}", ['Content-type' => 'application/json'], json_encode(['json' => ['nonce' => $headers['json']]]));
}

Also in docs for Psr7\Request enter image description here

like image 73
Zelf Avatar answered Nov 14 '22 23:11

Zelf


If you want full control, don't use the Request() object in your Pool. Instead, start the request yourself by having your pool's generator yielding a callable function which starts the request. That gives you total control of all options. Here is a correct code example:

https://stackoverflow.com/a/40622269/5562035

like image 40
gw0 Avatar answered Nov 14 '22 23:11

gw0