服务器发送的事件轮询导致长时间延迟 [英] Server-Sent Events Polling causing long delays

查看:240
本文介绍了服务器发送的事件轮询导致长时间延迟的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have a connector that will call a RESP API using cURL and PHP.

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

I need to call one method every second to check for new messages and then process them. I used the following 2 approaches to handle the messages


  1. AJAX轮询使用 SetInterval():每秒调用一次php脚本。这完全有效,除了我无法阻止多个 SetInterval()从浏览器的不同选项卡同时运行。 (我不想让用户打开10个浏览器标签,这导致一个用户有10个 SetInterval()同时运行。

  2. 服务器发送事件使用 EventSource :一旦队列中有新数据,服务器将发送更新浏览器。这会减慢响应时间。脚本需要大约20多秒才能完成,这是一个问题。我不知道为什么会发生这种情况。

  1. AJAX Polling using SetInterval(): call the php script once every second. This works perfectly except I am unable to prevent multiple SetInterval() from running at the same time from different tabs of the browser. ( I don't want to have user opens 10 browser tabs which leads to one user having 10 SetInterval() are running at the same time.
  2. Server Sent Events using EventSource: The server will send update the browser once there are new data in the queue. This slows down the respond time. Every call I make to the script takes about 20+ seconds to complete which is a problem. I am not sure why this is happening.

这是我的 SetInterval() implementation

Here is my SetInterval() implementation

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

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

    }, 1000);
}

用户登录后我调用此函数 startCalls()

once a user logs in I calls this function startCalls()

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

inside the index.php file I have this code to be called

if($method == 'getMessages'){

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

}

这是我的第二个实施服务器发送事件

Here is my second implementation "Server-Sent Events"

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

once a user logs in I calls this function startPolling( new EventSource("poll.php") );

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

For the sake of simplicity, assume that my processServerData method looks like this

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


?>

服务器似乎锁定所有命中服务器的请求,直到页面刷新停止无限循环一旦我刷新页面,其他请求就会立即显示进程

The server seems to lock all requests that hit the server until the infinite loop is stopped by "page refresh" as soon as I refresh the page the other requests are processes immediately

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

Why would the Server-Sent Event cause such an issue?

针对不同类型的极化的一个很好的资源可以在这个问题中找到

A great resource for the different types of poling can be found in this Question

推荐答案

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

Everything looks robust, so I'm going to take a guess that you are being hit by session locking. PHP sessions lock the session file, such that only one PHP script can use the session at a time; when you think about it, this is a great idea!

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

The problem with sessions and SSE is that the SSE PHP process runs forever, and therefore it locks the session forever. If any other PHP script tries to run with the same session, it will block (at the session_start() call, I believe).

这看起来像一篇好文章就此主题而言;一旦你知道更长时间需要会话,建议就是调用 session_write_close()。例如。如果您只是需要使用会话来检查他们以前是否已经授权,那么在您之后直接调用 session_write_close(),其他进程将不会被阻止。

This looks like a good article on the subject; the advice is to call session_write_close() once you know longer need the session. E.g. if you just need to use the session to check they have previously authorized themselves, then straight after that you call session_write_close(), and other processes will not get blocked.

这篇关于服务器发送的事件轮询导致长时间延迟的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆