Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to match a result to a request when sending multiple requests?

Tags:

guzzle

A. Summary

As its title, Guzzle allows to send multiple requests at once to save time, as in documentation.

$responses = $client->send(array(
    $requestObj1,
    $requestObj2,
    ...
));

(given that each request object is an instance of
Guzzle\Http\Message\EntityEnclosingRequestInterface)

When responses come back, to identify which response is for which request, we can loop through each request and get the response (only available after executing the above command):

$response1 = $requestObj1->getResponse();
$response2 = $requestObj2->getResponse();
...

B. Problem

If the request object contains the same data. It's impossible to identify the original request.

Assume we have the following scenario where we need to create 2 articles: A and B on a distance server: something.com/articles/create.json

Each request has same POST data:

subject: This is a test article

After created, the Guzzle responses with 2 location come back:

something.com/articles/223.json
something.com/articles/245.json

Using the above method to link response-to-its-request, we still don't know which response is for which article, because the request object is exactly the same.

Hence in my database I cannot write down the result:

article A -> Location: 245.json
article B -> Location: 223.json

because it can be the other way arround:

article A -> Location: 223.json
article B -> Location: 245.json

A solution is to put some extra parameter in the POST request, e.g.

subject: This is a test article
record: A

However, the distance server will return error and does not create article because it does not understand the key "record". The distance server is a third party server and I cannot change the way it works.

Another proper solution for this is to set some specific id/tag on the request object, so we can identify it afterwards. However, I've looked through the documentation but there is no method to uniquely identity the request like

$request->setID("id1")

or

$request->setTag("id1")

This has been bugging me for months and still cannot resolve this issue.

If you have solution, please let me know.

Many many thanks and you've saved me!!!!

Thanks for reading this long post.

like image 964
markbse Avatar asked Oct 01 '22 05:10

markbse


1 Answers

I've found a proper way to do it, Guzzle allow to add callback once a request is completed. So we can achieve this by setting it on each request in the batch

Each request by default can be created like this

$request = $client->createRequest('GET', 'http://httpbin.org', [
    'headers' => ['X-Foo' => 'Bar']
]);

So, to achieve what we want:

$allRequests = [];
$allResults = [];

for($k=0; $k<=10; $k++){
    $allRequests['key_'.$k] = $client->createRequest('GET', 'http://httpbin.org?id='.$k, [
        'headers' => ['X-Foo' => 'Bar'],
        'events' => [
            'complete' => function ($e) use (&$allResults, $k){
                $response = $e->getResponse();
                $allResults['key_'.$k] = $response->getBody().'';
            }
        ]
    ]);
}

$client->sendAll(array_values($allRequests));

print_r($allResults);

So now the $allResults has result for each corresponding request.

e.g. $allResults['key_1'] is the result of $allRequests['key_1']

like image 197
markbse Avatar answered Oct 05 '22 13:10

markbse