MultiCurl::proceed is now blocking
lyrixx opened this issue · comments
Before version 1 (beta) MultiCurl::proceed()
was non-blocking, and now it's a blocking call.
It waits until all requests finish.
<?php
use Buzz\Client\MultiCurl;
use Nyholm\Psr7\Factory\MessageFactory;
use Nyholm\Psr7\Factory\Psr17Factory;
use Nyholm\Psr7\Request;
require __DIR__.'/vendor/autoload.php';
$client = new MultiCurl(new Psr17Factory());
$client->sendAsyncRequest($a = new Request('GET', 'http://httpbin.org/delay/1'), ['callback' => function($request, $response, $exception) {
dump('A');
dump(time() - $_SERVER['REQUEST_TIME_FLOAT']);
// echo $response->getBody()->getContents();
}]);
$client->sendAsyncRequest($a = new Request('GET', 'http://httpbin.org/delay/2'), ['callback' => function($request, $response, $exception) {
dump('B');
dump(time() - $_SERVER['REQUEST_TIME_FLOAT']);
// echo $response->getBody()->getContents();
}]);
$client->sendAsyncRequest($a = new Request('GET', 'http://httpbin.org/delay/3'), ['callback' => function($request, $response, $exception) {
dump('C');
dump(time() - $_SERVER['REQUEST_TIME_FLOAT']);
// echo $response->getBody()->getContents();
}]);
while (true) {
$client->proceed();
echo '.';
usleep(100000);
}
Thank you for this issue.
I've spent a few hours yesterday working on this. Currently, proceed
works as flush
. This is indeed breaking change.
However, can you explain the use case for a non-blocking proceed
function?
I will document the methods better and resolve this.
I will try to explain what I do with multi-curl:
I have built a Crawler that rely on AMQP, MultiCurl and other things.
Basically, I have a worker that grab URLs from AMQP. As soon as I fetch an URL, I init the HTTP Request (if I have enough room in my "HTTP Queue" (it's just an SplObjectStorage with a $maxItem property))
When the queue is full, I proceed the HTTP Queue to see if some request have finished.
If it's the case, I analyse the response(s) and so I free a place(s) for a next AMQP message(s) (it will create a new HTTP Request(s) that will be placed in the HTTP Queue.
Here is an extract of what I did (I removed some code, but the main idea is here):
while (true) {
// Listen for AMQP message: trigger HTTP request for them
while (!$httpQueue->isFull() && false !== $amqpEnvelope = $amqpQueue->get()) {
$resource = $this->startMessage($amqpEnvelope, $httpQueue, $crawl);
$httpQueue->add($resource, [
'amqpEnvelope' => $amqpEnvelope,
'amqpQueue' => $amqpQueue,
]);
}
// Check if HTTP request are finished
$this->crawler->tick(); // Will call $buzz->proceed();
// Process finished HTTP request
foreach ($httpQueue->popFinished() as [$resource, $data]) {
$this->processResponse($resource, $data['amqpEnvelope'], $data['amqpQueue']);
}
}
As you can guess, I do not want to wait until all response are available. As soon as I get a response after the tick
I proceed it and free a slot in the HTTP Queue.
With this workflow, I get really high performance, and almost everything is async
Thank you
I will fix these issues of yours this week. If you give up Buzz or not is irrelevant. =)
Do you know if there is something existing that could fit my use case?
Hm.. I dont think php-http/curl-client
or Guzzle have a similar proceed()
function. Maybe https://github.com/clue/reactphp-buzz could be worth looking into.
I've got a fix for your already. See the diff: https://github.com/kriswallsmith/Buzz/pull/356/files?utf8=%E2%9C%93&diff=split&w=1#diff-f07f8f3af40548280b3046caf5c568bfL119
It is super simple to provide fixes when you done half the work and written test code. Thank you!
Can you try master
to see if it is working?
If so, I'll tag beta2.
sure. I do that :)