服务器发送的事件轮询导致长时间延迟

时间:2015-06-16 17:10:47

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

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

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

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

    的绝佳资源

1 个答案:

答案 0 :(得分:3)

一切看起来都很健壮,所以我想猜一下你被会话锁定所打击。 PHP会话锁定会话文件,这样一次只有一个PHP脚本可以使用该会话;当你想到它时,这是一个好主意!

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

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