Search code examples
phpasynchronousslack

PHP waiting for curl to finish before returning


I have two PHP files, one for "heavy lifting", one for quick responses that marshals the request to the heavy lifter so that the quick response file may respond to server request immediately (at least, that is the goal). The premise for this is the Slack Slash commands that prefer an instant 200 to let user know command is running.

<?php
echo("I want this text to reply to server instantly");
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$code = '200';

$curl = curl_init();
curl_setopt_array($curl, array(
  CURLOPT_URL => "http://myheavyliftingfile.php",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => "datatobeusedbyheavylifter:data",
  CURLOPT_HTTPHEADER => array(
    "cache-control: no-cache",
    "content-type: application/x-www-form-urlencoded",
    "postman-token: 60757c65-a11e-e524-e909-4bfa3a2845fb"
  ),
));

$response = curl_exec($curl);
?>

What seems to be happening is, my response/echo doesn't get sent to Slack until my heavylifting.php curl finishes, even though I wish for my response to happen immediately, while the heavy-lifting process itself separately. How can I have one PHP file acknowledge the request, kick off another process on a different file, and respond without waiting for long process to finish?

Update

I do not wish to run multiple curls at once, I just wish to execute one curl but not wait for it to return in order to return a message to Slack to say I received the request. My curl sends data to my other php file that does the heavy lifting. If this is still the same issue as defined in the duplicate, feel free to flag it again and I won't reopen.


Solution

  • The reason this does not work is, that PHP curl calls are always synchronous and your timeout is set to 30 seconds, which far exceeds the max. 3 seconds that is allowed for Slash commands.

    But there is a fix to make this work. You just need these small changes:

    1. Set the curl timeout to a smaller value to ensure your first script is completing below the 3 second threshold, e.g. set CURLOPT_TIMEOUT_MS to 400, which defines a timeout of 400 ms.

    2. Set CURLOPT_NOSIGNAL to 1 in your first script. This is required for the timeout to work in UNIX based systems.

    3. Make sure to ignore timeout-errors (CURL ERROR 28) in your first script, since your curl should always return a timeout error.

    4. Make sure your second script is not aborted by the forced timeout by adding this line: ignore_user_abort(true);

    See also this answer for a full example.

    P.S.: You to not need any buffer flushing for this approach.