I'm doing POC implementation of async http requests in PHP. The symfony http client works well when we retrieve response data following way:
$response1 = $httpClient->request('GET', 'https://127.0.0.1:8000/service/a');
$response2 = $httpClient->request('GET', 'https://127.0.0.1:8000/service/b');
$array1 = $response1->toArray();
$array2 = $response2->toArray();
Considering both services A and B take 5 seconds to execute, our client code will have to wait only 5 seconds totally.
Now, the problem is that usually we write different repositories for different clients (RepositoryA, RepositoryB). Hence, in client code we won't operate on simple HttpResponseInterface object, but on some DTO instead.
I'd like to take advantage of async http requests, while retaining the repositories separation.
The simplified approach looks like this:
private function getResponse1(): Generator
{
$response1 = $this->httpClient->request('GET', 'https://127.0.0.1:8000/service/a');
return yield $response1->toArray();
}
private function getResponse2(): Generator
{
$response2 = $this->httpClient->request('GET', 'https://127.0.0.1:8000/service/b');
return yield $response2->toArray();
}
$response1 = $this->getResponse1();
$response2 = $this->getResponse2();
$array1 = $response1->current();
$array2 = $response2->current();
If you are familiar with JS, this current()
call on Generator
object is somewhat similar to await
construct.
Finally, the question is why doesn't this approach work? Since measurements show that total time is 10 seconds of waiting with generators, while only 5 seconds without them.
Here's the Console command, which may be used to reproduce the issue: https://github.com/rela589n/generator-as-promise-poc/blob/master/src/Command/TestSyncSfClientGeneratorsCommand.php
Ans also there's a working example of code not using generators: https://github.com/rela589n/generator-as-promise-poc/blob/master/src/Command/TestAsyncSfHttpClientCommand.php