PHP SSE (EventSource) 每 2 分钟超时一次

发布于 2025-01-15 22:47:51 字数 2467 浏览 5 评论 0原文

  1. 我正在使用这个 Mozilla SSE 示例
  2. 我在循环内添加了一个示例 PHP proc_open 示例。
  3. 从浏览器运行,一切正常。

唯一的问题是 proc_open() 执行一个可能需要 2 分钟以上才能完成的命令,这使得浏览器仅在 2 分钟后超时。我们的服务器使用非线程PHP。

问题:

如何让 PHP 脚本在等待 proc_open() 在非线程 PHP 脚本中完成时向浏览器发送某些内容?

代码:

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);
}
  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);
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

爱的那么颓废 2025-01-22 22:47:51

我在我的一个项目中遇到了这样的问题,因此请在脚本的开头使用这一行 set_time_limit(0); ,如下所示

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

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
泅渡 2025-01-22 22:47:51

解决方法

如果有人遇到同样的问题,我采用了此解决方法,即在您的实际命令正在运行并等待完成时向浏览器发送“Ping”。

MyScript.sh:

#!/bin/bash

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

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

使用:

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

如果您正确设置了 SSE,您的浏览器将在命令运行的同时每 30 秒收到一次“Ping”,因此您的浏览器永远不会暂停。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文