4

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Patrick Lambe
  • 283
  • 2
  • 13
  • 1
    Have you tried flushing the output buffer before starting the curl statement? http://php.net/manual/en/function.ob-flush.php – ivanivan Jan 06 '18 at 01:04
  • hi ivanivan, just tried flushing the buffer but no avail. thanks @barmar, question on the marked dupe, that will allow me to conduct multiple curl requests at the same time, but will it allow me to return a 200 to the server before each of the curl requests have finished? If it does, then yes this is a dupe, if not, then my issue may be slightly different. I do not wish to create multiple curls and have them execute at same time, I wish to return after kicking off a curl request and not wait for it to complete as my other php file takes care of that. – Patrick Lambe Jan 06 '18 at 01:21
  • This is just a simpler case of the same thing. What's the difference between doing multiple requests without waiting for them to complete and doing one request without waiting for it to complete? – Barmar Jan 06 '18 at 01:25
  • Actually, I see the issue. That solution uses threads, but I don't think the main script will complete until all the threads complete. So a different solution is needed if you don't want to wait at all. – Barmar Jan 06 '18 at 01:27
  • Thanks Barmar, yes I believe that's the issue I have, I don't wish to wait atall, as opposed to wanting to save time by running multiple curls at once. Sorry it wasn't clear in first instance. Maybe what I'm looking for isn't possible in PHP but thought I would check. – Patrick Lambe Jan 06 '18 at 01:31
  • This is largely a duplicate of https://stackoverflow.com/questions/36171222/async-curl-request-in-php. – Luke Waite Jan 06 '18 at 03:47
  • Thanks @LukeWaite. In that above link, am I right in saying that, while it allows for async processing of multiple curls, the curls are all required to complete before the script can return? – Patrick Lambe Jan 06 '18 at 12:25

1 Answers1

4

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.

Erik Kalkoken
  • 30,467
  • 8
  • 79
  • 114