Guzzle and asynchronous requests in PHP

Asked

Viewed 967 times

2

I was taking a look at the documentation of GuzzleHttp and I saw that there is an explanation on how to use it to make asynchronous requests.

$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
$promise->then(function ($response) {
    echo 'Got a response! ' . $response->getStatusCode();
});

I did some tests exactly as in the example, and did not get the expected return. A Closure which is the argument of then doesn’t work.

How does this asynchronous request work on Guzzle?

Is there any way to do them in PHP (as in Ajax), or is another story (the concepts are different)?

  • Usually the technique used is to execute a shell command. In your case, it may be that the library has some bug or is not able to detect the operating system properly to apply a proper command. The command varies between Linux distributions and also Windows. Make sure that’s not the problem.

1 answer

3


As far as I know PHP does not support asynchronous events natively, precisely because it is synchronous, ie it is a layer of requisition and reply and I don’t see so much need to run two events at the same time.

About your problem maybe it’s the lack of wait();, The Guzzle documentation says that the use is with PSR-7 thus:

$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org/get');
$promise = $client->sendAsync($request)->then(function ($response) {
    echo 'I completed! ' . $response->getBody();
});
$promise->wait();

anyway for the front-end this will be imperceptible and for the server I do not see the "advantage" of using this, because the larger layer of the script will still have to wait for the events to end (when to use wait();).

I do not know what means they use, but if you want to study on the subject there is:

https://stackoverflow.com/a/13872965/1518921

Also has reactPHP as said here Run PHP function asynchronously

Async hack (hhvm)

In the hack language (hhvm) there are asynchronous methods:

However for the answer you will not feel changes (I believe), but in the back-end it is as if it were more than one Thread and so can perform more than one task without expecting another, example (only works with <?hh):

<?hh

namespace Hack\UserDocumentation\Async\Intro\Examples\Limtations;

async function do_cpu_work(): Awaitable<void> {
  print("Start CPU work\n");
  $a = 0;
  $b = 1;

  $list = [$a, $b];

  for ($i = 0; $i < 1000; ++$i) {
    $c = $a + $b;
    $list[] = $c;
    $a = $b;
    $b = $c;
  }
  print("End CPU work\n");
}

async function do_sleep(): Awaitable<void> {
  print("Start sleep\n");
  sleep(1);
  print("End sleep\n");
}

async function main(): Awaitable<void> {
  print("Start of main()\n");
  await \HH\Asio\v([
    do_cpu_work(),
    do_sleep(),
  ]);
  print("End of main()\n");
}

\HH\Asio\join(main());

PHP CLI

An alternative would be to execute a command as if it were in the terminal and wait or not the answer remembering the async, I did this for a very specific case, where there was a script that when processing consumed a lot of Apache, so using exec I did something like this:

  • Windows, one should run something like:

    set QUERY_STRING="foo=1&bar=2"
    start /B cmd /S /C php -c php.ini c:/wamp/www/arquivo.php
    

    The start /B cmd /S /C is to wait for the command to end.

  • Like-Unix, one should run something like:

     export QUERY_STRING="foo=1&bar=2";
     php -c php.ini "/etc/www/arquivo.php";
    

The whole script looked like this (note that I did this script some time ago, if it fails let me know):

function async($phpScript, $query_string='') {
    $php_exe = 'php';

    $iniFile = php_ini_loaded_file();

    if (false === $iniFile) {
        echo 'Erro ao carregar php.ini not loaded (php_ini_loaded_file = false)';
        exit;
    } else if (false === file_exists($phpScript)) {
        echo 'Script não econtrado: ' . $phpScript;
        exit;
    }

    $output = array();
    $exec = '';

    if (stripos(PHP_OS, 'WIN') !== false) {
        foreach ($_SERVER as $key => $value) {
            if ($key !== 'HTTP_ACCEPT_ENCODING' && $key !== 'QUERY_STRING') {
                $exec .= 'set ' . $key . '=' . escapeshellcmd($value) . '& ';
            }
        }

        $exec .= 'set QUERY_STRING=' . escapeshellcmd($query_string) . '& ';
        $exec .= 'start /B cmd /S /C php ' . escapeshellcmd(' -c ' . $iniFile . ' ' . $phpScript);
    } else {
        foreach ($_SERVER as $key => $value) {
            if ($key !== 'HTTP_ACCEPT_ENCODING' && $key !== 'QUERY_STRING') {
                $exec .= 'export ' . $key . '=' . escapeshellarg($value) . '; ';
            }
        }

        $exec .= 'export QUERY_STRING=' . escapeshellarg($query_string) . '; ';
        $exec .= 'php -c ' . escapeshellarg($iniFile) . ' ' .
                    escapeshellarg($phpScript);// . ' >/dev/null 2>&1 &';
    }

    exec($exec, $output, $status);

    return array(
        'status' => $status,
        'command' => $exec,
        'output'  => $output
    );
}

I commented on the >/dev/null 2>&1 & because in Debian6 (at the time) I had some problem, but you can use it in the terminal like this:

 export QUERY_STRING="foo=1&bar=2";
 php -c php.ini "/etc/www/arquivo.php" >/dev/null 2>&1 &

This is not quite "asynchronous" for the script, but it is possible to run files that consume more memory without affecting Apache and Ngnix for example, because it runs separately, I know it’s not quite what you asked for, but I’m not sure what your need really is.

  • I need to make several requests on a webservice (which is slow) without affecting the page load speed. I imagined that there was really no way to leave "asynchronous php", I really wanted to understand what the purpose of guzzle was to do this. I think it’s worth looking at the threads

  • @Wallacemaxters with async or without the speed of delivery to the customer-side is the same, the only improvement will be if you want to run two webservices on a request, but probably the memory consumption or processor will increase. These async solutions are not always necessary. If you have a problem with I/O because a page loading a webservice crashes other requests read this: http://answall.com/a/57827/3635

Browser other questions tagged

You are not signed in. Login or sign up in order to post.