WordPress / Requests

Requests for PHP is a humble HTTP request library. It simplifies how you interact with other sites and takes away all your worries.
https://requests.ryanmccue.info/
Other
3.57k stars 497 forks source link

blocking => false not working #826

Open peixotorms opened 1 year ago

peixotorms commented 1 year ago

Summary

When I set blocking => false, the request is still blocking.

Given the following code sample

# make options
    $options = array(
        'timeout' => 60,
        'connect_timeout' => 10,
        'blocking' => false
    );

# request
$response = WpOrg\Requests\Requests::request($url, $headers, $data, POST, $options);

Unfortunately, if I set a short timeout like 1 second, the remote API call will not complete. I don't need the response, only for it to run in the background while the script does something else.

I'd expect the following behaviour

I would expect it to return immediately, so the rest of the script can run.

Instead this happened

With a long API call lasting over 1 minute, the script hangs until it returns a reply.

Additional context

The way around this for non blocking requests is to use curl with CURLOPT_NOSIGNAL set to 1. This let's me timeout early and the api call will complete properly.

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $endpoint);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 1); // Set timeout to 1 second
curl_setopt($ch, CURLOPT_NOSIGNAL, 1); // Ignore all cURL signals to ensure script continues 
curl_exec($ch);
curl_close($ch);

Your environment

Environment Answer
Operating system and version: Ubuntu 22.04
PHP version 8.2 lsapi, openlitespeed
Requests version v2.0.7

Tested against develop branch?

no

schlessera commented 11 months ago

@peixotorms I cannot replicate this. When using 'blocking' => false, Requests bails early on a request with an empty Response object. You can see this for example when checking that the 'status' in the response is false.

image

Can you provide more information or a piece of content that lets us replicate this?

peixotorms commented 11 months ago

Hi, it's been over 3 months, so I don't remember the exact case, but If I remember correctly, when you call an external url that takes for example 10 seconds to complete the output, it was also slowing down the response on the calling script, regardless of the blocking settings.

So script A calls script B with blocking = false, but script B needs 10 seconds to complete. Script A would then take at least 10 seconds to finish as well.

Adding CURLOPT_NOSIGNAL when blocking = false, sorted it for me though.

I'll test this again against the latest version soon, but not right now.

Thanks

emohamed commented 6 months ago

@schlessera the problem is reproducible for me. It's apparent if you use an endpoint that takes longer to produce a response, like https://httpbin.org/delay/5:

$ wp eval --skip-wordpress '
    $start = microtime(true);
    $response = WpOrg\Requests\Requests::request( "https://httpbin.org/delay/5", [], [], "GET", [ "blocking" => false, "verify" => false ]  );
    print_r($response);
    echo "Request took: " . (microtime(true) - $start ) . " seconds";'

WpOrg\Requests\Response Object
(
    [body] =>
    [raw] =>
    [headers] => WpOrg\Requests\Response\Headers Object
        (
            [data:protected] => Array
                (
                )

        )

    [status_code] =>
    [protocol_version] =>
    [success] =>
    [redirects] => 0
    [url] =>
    [history] => Array
        (
        )

    [cookies] => WpOrg\Requests\Cookie\Jar Object
        (
            [cookies:protected] => Array
                (
                )

        )

)
Request took: 5.6029760837555 seconds

The response is indeed empty, however the library is awaiting for it.

schlessera commented 6 months ago

@peixotorms @emohamed Thanks, I can indeed replicate this.

Using CURLOPT_NOSIGNAL can introduce other problems, though, as this means that cURL skips registering any signal handlers. The most obvious issue there will be that DNS timeouts will not be caught and just go on indefinitely, unless you catch these yourself.