Send asynchronous request without waiting the response using guzzle
Asked Answered
U

5

24

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.

Undamped answered 12/3, 2016 at 10:31 Comment(4)
I got an answer here github.com/guzzle/guzzle/issues/1429#issuecomment-197119452Undamped
Please answer your own question with what worked for you, and accept it as the correct answer to help others.Drank
better use rabbit mqInterlocutory
@Undamped The answer github.com/guzzle/guzzle/issues/1429#issuecomment-197152914 uses 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.Celindaceline
V
13

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

Variola answered 27/6, 2017 at 7:56 Comment(1)
last part of the title is "using guzzle"Variola
F
9

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.

Fouquet answered 21/10, 2021 at 9:41 Comment(2)
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.Epiblast
launch exception with error "Operation timed out after 1004 milliseconds with 0 bytes received"Brandon
C
0

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.

Cheroot answered 8/8, 2019 at 14:36 Comment(5)
Working for me. I don't know why did this answer got down votedVickeyvicki
Probably because it's not using guzzle and even php and is using exec function which is not a good idea.Exorbitant
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.Cheroot
You should be wrapping $url in escapeshellarg() for safety. — @benhardh Best if you could please update the answer, too.Gluteus
Have added it now.Cheroot
C
-1

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

$client = new GuzzleClient();
$promise = $client->getAsync($url)
$promise->then();
Ciliary answered 14/11, 2019 at 7:42 Comment(0)
M
-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.

Masterly answered 15/6, 2022 at 14:59 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.