gmponos
gmponos

Reputation: 2277

Send asynchronous request without waiting the response using guzzle

I have the following two functions

public function myEndpoint(){
    $this->logger->debug('Started');
    $this->guzzle->requestAsync('post', 'http://myurl.com/doNotWait')->wait();
    $this->logger->debug("I shouldn't wait");
}

public function doNotWait(){
    sleep(10);
    $this->logger->debug("You shouldn't wait");
}

Now what I need to see in my logs is:

Started
I shouldn't wait
You shouldn't wait

But what I see

Started
You shouldn't wait
I shouldn't wait

Also I tried using the following ways:

Way #1

public function myEndpoint(){
    $this->logger->debug('Started');
    $this->guzzle->requestAsync('post', 'http://myurl.com/doNotWait', ['synchronous' => false])->wait();
    $this->logger->debug("I shouldn't wait");
}

Way #2

public function myEndpoint(){
    $this->logger->debug('Started');
    $this->guzzle->requestAsync('post', 'http://myurl.com/doNotWait');

    $queue = \GuzzleHttp\Promise\queue()->run();
    $this->logger->debug("I shouldn't wait");
}

But the result is never the desired one. Any idea? I am using Guzzle 6.x.

Upvotes: 25

Views: 29092

Answers (5)

bernhardh
bernhardh

Reputation: 3309

Since others wrote, that Guzzle doesn't offer a build in solution for this, here is a solution as one liner:

$url = escapeshellarg("http://myurl.com/doNotWait");
exec("wget -O /dev/null -o /dev/null " . $url . " --background")

It uses exec (https://www.php.net/manual/de/function.exec.php) to run the commandline tool wget (https://de.wikipedia.org/wiki/Wget - its included in most linux distries and also works in Windows and OSX) command. I have tested it only on linux, so maybe the params have to be adjusted for your OS.

Lets split it up into parts

  • -O /dev/null: The result of the request should be send to null (nowhere)
  • -o /dev/null: The logs should be send to null
  • $url: The url you wanna call, for example http://myurl.com/doNotWait
  • --background: Run in background, do not wait.

For those who think "exec" is evil: If the params are from an user input, you could be right. If the url is defined by your code, then its not.

Upvotes: 0

Otoniel Silva
Otoniel Silva

Reputation: 37

As request fire and forget. One of the solutions worked for me.

 $client = new \GuzzleHttp\Client(['timeout' => 0.001]);        
 $promise = $client->requestAsync('GET', 'http://dummy.site');

 try {
        $promise->wait();
 } catch (\Exception $ex) {
        ## Handle                       
 }

If $promise->wait(); is not called the request was not performed.

Upvotes: -2

Sergey Onishchenko
Sergey Onishchenko

Reputation: 7851

If you don't care about the response, the following should do:

try {
    $this->guzzle->post('http://myurl.com/doNotWait', ['timeout' => 1]);
} catch (\GuzzleHttp\Exception\ConnectException $e) {
    // do nothing, the timeout exception is intended
}

So, here the request will take 1 sec and the code execution will continue.

Upvotes: 9

Dror Dromi
Dror Dromi

Reputation: 163

Make asynchronous call to create promise then call then() method with no callbacks

$client = new GuzzleClient();
$promise = $client->getAsync($url)
$promise->then();

Upvotes: -1

cweiske
cweiske

Reputation: 31068

To get it off the unanswered list:


Guzzle does not support "fire and forget" asynchronous requests without deep hacking.

The async methods are abstractions for Client::requestAsync(), which returns a promise. See https://github.com/guzzle/promises#synchronous-wait - calling Promise::wait() "is used to synchronously force a promise to complete".

Reference: https://github.com/guzzle/guzzle/issues/1429#issuecomment-197119452

Upvotes: 13

Related Questions