23

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.

gmponos
  • 2,157
  • 4
  • 22
  • 33
  • 3
    I got an answer here https://github.com/guzzle/guzzle/issues/1429#issuecomment-197119452 – gmponos Mar 16 '16 at 07:14
  • 4
    Please answer your own question with what worked for you, and accept it as the correct answer to help others. – Yep_It's_Me Apr 07 '17 at 02:36
  • 1
    better use rabbit mq – bxN5 May 03 '17 at 14:38
  • @gmponos The answer https://github.com/guzzle/guzzle/issues/1429#issuecomment-197152914 uses https://github.com/WyriHaximus/react-guzzle-psr7 which is now deleted. Can you answer your question with a Guzzle 7 versions? I've been looking for working async code for days. – James Risner Feb 03 '23 at 01:35

5 Answers5

12

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

cweiske
  • 30,033
  • 14
  • 133
  • 194
6

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.

Sergey Onishchenko
  • 6,943
  • 4
  • 44
  • 51
  • This is great. I tried with GET and tried to construct a recursion, which might be useful as some kind of cron alternative. I had to also set 'connect_timeout' and 'read_timeout' though. And once a process was stuck, I had to restart the web server. The thing seems a bit fragile if you use very small wait times, e.g. with 0.001 it did not work. But some problems might have been caused by xdebug, which I needed to check what his happening. – donquixote Apr 13 '23 at 20:33
0

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

$url = "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.
bernhardh
  • 3,137
  • 10
  • 42
  • 77
  • Working for me. I don't know why did this answer got down voted – Manitra Andriamitondra Aug 22 '20 at 07:39
  • 2
    Probably because it's not using guzzle and even php and is using exec function which is not a good idea. – Steve Moretz Mar 18 '21 at 10:01
  • 3
    The question mentioned guzzle, but doesn't say "only guzzle related answers allowed". Using `exec` isn't the preferred way doing things, but as long there is no (unfiltered) user input involved and the rights of the user of the running scripts are correct, it is a valid fallback strategy. – bernhardh Mar 18 '21 at 10:09
0

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

$client = new GuzzleClient();
$promise = $client->getAsync($url)
$promise->then();
Dror Dromi
  • 157
  • 1
  • 4
-2

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.