【问题标题】:Server-Sent Events Polling causing long delays服务器发送事件轮询导致长时间延迟
【发布时间】:2015-06-16 17:10:46
【问题描述】:

我有一个连接器,它将使用 cURL 和 PHP 调用 RESP API。

我需要每秒调用一个方法来检查新消息然后处理它们。我使用以下两种方法来处理消息

  1. 使用SetInterval() 进行AJAX 轮询:每秒调用一次php 脚本。这非常有效,除非我无法阻止多个SetInterval() 从浏览器的不同选项卡同时运行。 (我不想让用户打开 10 个浏览器选项卡,这会导致一个用户同时运行 10 个 SetInterval()
  2. 服务器使用EventSource 发送事件:一旦队列中有新数据,服务器将发送更新浏览器。这会减慢响应时间。我对脚本的每次调用都需要大约 20 多秒才能完成,这是一个问题。我不确定为什么会这样。

这是我的SetInterval() 实现

function startCalls(){
    //update the screen using Intervals
    refreshIntervalId = setInterval(function() {

        $.getJSON("index.php", {'method': 'getMessages', 'jSON': true} , function(data){
            processServerData(data);
         });

    }, 1000);
}

一旦用户登录,我就会调用这个函数startCalls()

在 index.php 文件中我有这个代码被调用

if($method == 'getMessages'){

    $messaging = new ICWS\Messaging($icws);
    $messaging->processMessages();
    $myQueue = $messaging->getCallsQueue();
    echo json_encode($myQueue );

}

这是我的第二个实现“服务器发送事件”

//Server Side Message Polling
function startPolling(evtSource){

    evtSource.addEventListener("getMessagingQueue", function(e) {

        var data = JSON.parse(e.data);
        processServerData(data)
    }, false);
}

一旦用户登录,我就会调用这个函数startPolling( new EventSource("poll.php") );

为简单起见,假设我的processServerData 方法如下所示

function processServerData(data){
    console.log('process the data received from the server');
}

这是我的 php 代码

<?php

    require 'autoloader.php';

    //Make sure cURL is enabled on the server
    if(!is_callable('curl_init')){
        exit('cURL is disabled on this server. Before making API calls cURL extension must be enabled.');
    }

    if( isset($_COOKIE['icws_username']) ){
        $user = trim($_COOKIE['icws_username']);
    }

    if( isset($_COOKIE['icws_password']) ){
        $pass = trim($_COOKIE['icws_password']);
    }

    if( isset($_COOKIE['icws_station']) ){
        $stationName = trim($_COOKIE['icws_station']);
    }

    if( !isset($user, $pass, $stationName) ){
        echo json_encode(array('status' => 'The IC credentials you entered are invalid')); 
        exit;
    }

    $scheme = 'http';
    $host   = 'host';
    $port   = '8018';
    $sleepTime = 1;
    $url = sprintf('%s://%s:%s@%s:%s', $scheme, $user, $pass, $host, $port);

    try {
        header("Content-Type: text/event-stream\n\n");
        session_start();

        //configure the connection
        $conf = new ICWS\Config\Config($url, $stationName); 

        //create a new instance of icws
        $attrebutes = array();
        $icws = new ICWS\Connection($conf, $attrebutes, true); 

        $messaging = new ICWS\Messaging($icws);

    ob_end_clean();
    while(true){

        header("Content-Type: text/event-stream" . PHP_EOL);
        header("Cache-Control: no-cache" . PHP_EOL);

        $messaging->processMessages();
        $result = $messaging->getCallsQueue();

        //$current = $icws->getCurrentUserStatusQueue();
        echo 'event: getMessagingQueue' . PHP_EOL;
        echo 'data: ' . json_encode( $result) . PHP_EOL;    
        echo PHP_EOL; //required  

        ob_end_flush();
        flush(); 
        sleep(1);

    }

    } catch(Exception $e){
        echo $e->getMessage();
    }


?>

服务器似乎锁定了所有命中服务器的请求,直到我刷新页面后,“页面刷新”停止无限循环,其他请求立即处理

为什么 Server-Sent Event 会导致这样的问题?

不同类型的投票的绝佳资源can be found in this Question

【问题讨论】:

    标签: javascript php jquery server-sent-events icws


    【解决方案1】:

    一切看起来都很健壮,所以我猜测您正在受到会话锁定的影响。 PHP会话锁定会话文件,这样一次只有一个PHP脚本可以使用会话;仔细想想,这是个好主意!

    会话和 SSE 的问题是 SSE PHP 进程永远运行,因此它永远锁定会话。如果任何其他 PHP 脚本尝试在同一会话中运行,它将阻塞(我相信在 session_start() 调用时)。

    这个主题看起来像a good article;建议是在您知道不再需要该会话时致电session_write_close()。例如。如果你只需要使用会话来检查他们之前是否已经授权自己,然后你直接调用session_write_close(),其他进程不会被阻塞。

    【讨论】:

    • 哇,非常感谢您的回答。我认为这是问题所在。但现在的问题是我必须将我的session_start() 放在循环的开头,将session_write_close() 放在循环的结尾,这给了我另一个问题Warning: session_start(): Cannot send session cache limiter - headers already sentNotice: ob_end_flush(): failed to delete and flush buffer. No buffer to delete or flush i 关于如何解决这个问题的任何想法有问题吗?
    • 哎呀,你真的需要每次迭代都有一个活跃的会话吗?您不能将会话中所需的值保存到程序顶部的局部变量中,然后使用它们吗?或者您是否需要写入会话,和/或从中读取最新值? (session_start() 警告是因为它试图再次发送会话 cookie,但失败了;您可以使用 @ 安全地抑制它。)
    • 不幸的是,在我的情况下,我必须每秒更新一次会话,然后阅读它。它是接收消息的缓存机制。我所做的是禁用此页面作为解决方法的错误。再次感谢您的帮助。如果我能给你 +100 票,我会:)
    猜你喜欢
    • 2013-01-04
    • 2012-03-12
    • 1970-01-01
    • 2016-07-25
    • 2012-06-03
    • 2023-04-10
    • 2017-09-30
    • 1970-01-01
    • 2010-11-08
    相关资源
    最近更新 更多