Home > database >  PHP SSE (EventSource) timeout every 2 minutes
PHP SSE (EventSource) timeout every 2 minutes

Time:03-22

  1. I'm using this Mozilla SSE example
  2. I added inside the loop a sample PHP proc_open example.
  3. Run from browser, everything works fine.

The only problem is proc_open() execute a command that can take more than 2 minute to finish, which make the browser timeout after 2 minutes only. And our server use non-thread PHP.

Question:

How I can make the PHP script send something to the browser while waiting for proc_open() to finish in a non-thread PHP script ?.

Code:

date_default_timezone_set("America/New_York");
header("Cache-Control: no-store");
header("Content-Type: text/event-stream");

$counter = rand(1, 10);
while (true) {
    // Run a local command
    $descriptorspec = array(
       0 => array("pipe", "r"),  // stdin is a pipe that the child will read from
       1 => array("pipe", "w"),  // stdout is a pipe that the child will write to
       2 => array("file", "/tmp/error-output.txt", "a") // stderr is a file to write to
    );
    
    $cwd = '/tmp';
    $env = array('some_option' => 'aeiou');
    
    $process = proc_open('HelloWorldProgram', $descriptorspec, $pipes, $cwd, $env);
    
    if (is_resource($process)) {
        // $pipes now looks like this:
        // 0 => writeable handle connected to child stdin
        // 1 => readable handle connected to child stdout
        // Any error output will be appended to /tmp/error-output.txt
    
        fwrite($pipes[0], '<?php print_r($_ENV); ?>');
        fclose($pipes[0]);
    
        echo stream_get_contents($pipes[1]);
        fclose($pipes[1]);
    
        // It is important that you close any pipes before calling
        // proc_close in order to avoid a deadlock
        $return_value = proc_close($process);
    
        echo "command returned $return_value\n";
    }


    // Every second, send a "ping" event.
    
    echo "event: ping\n";
    $curDate = date(DATE_ISO8601);
    echo 'data: {"time": "' . $curDate . '"}';
    echo "\n\n";
    
    // Send a simple message at random intervals.
    
    $counter--;
    
    if (!$counter) {
    echo 'data: This is a message at time ' . $curDate . "\n\n";
    $counter = rand(1, 10);
    }
    
    ob_end_flush();
    flush();
    
    // Break the loop if the client aborted the connection (closed the page)
    
    if ( connection_aborted() ) break;
    
    sleep(1);
}

CodePudding user response:

I had a problem like this in one of my project so use this line set_time_limit(0); in the start of your script like this

date_default_timezone_set("America/New_York");
header("Cache-Control: no-store");
header("Content-Type: text/event-stream");
set_time_limit(0);//this will prevent the script to stop

CodePudding user response:

Workaround

If someone had the same issue, I did this workaround which send a "Ping" to the browser while your real command is running and waiting to finish.

MyScript.sh:

#!/bin/bash

for task in "$@"; do {
  $task &
} done

while true; do {
  echo "Ping";
  sleep 30;
} done

Use:

$ sh MyScript.sh "Your Command Here With All Arguments"
Ping
Ping
Ping

If you setup correctly the SSE, you browser will receive "Ping" every 30 seconds in the same time your command is running so your browser will never timeout.

  • Related