长时间轮询挂起了所有其他服务器请求

时间:2019-05-01 15:25:11

标签: javascript php apache

我在我的网站上有一个简单的长轮询请求,以检查是否有任何新通知可用于用户。就请求而言,一切似乎都可以完美地工作。仅在更新数据库(并且已为该特定用户创建通知)后,该请求才得到满足,然后立即发出新请求。

问题


我注意到的是,当请求正在等待数据库的响应时(应该进行长时间轮询),对服务器的所有其他请求也会 挂起-不管是媒体文件,< strong> AJAX 请求,甚至正在加载新页面。这意味着对服务器的 all 请求将一直挂起,直到我关闭浏览器并重新打开它。

甚至更陌生的是,如果我访问我的localhost个站点中的另一个(我的长期民意调查位于MAMP虚拟主机站点www.example.com上),它们没有问题,我仍然可以使用它们好像什么都没发生-尽管它们在技术上在同一服务器上。

我的代码


这是我在客户端(longpoll.js)所拥有的:

window._Notification = {
    listen: function(){
        /* this is not jQuery's Ajax, if you're going to comment any suggestions, 
        *  please ensure you comment based on regular XMLHttpRequest's and avoid
        *  using any suggestions that use jQuery */
        xhr({
            url: "check_notifs.php",
            dataType: "json",
            success: function(res){
                /* this will log the correct response as soon as the server is 
                *  updated */
                console.log(res);
                _Notification.listen();
            }
        });
    }, init: function(){
        this.listen();
    }
}

/* after page load */
_Notification.init();

这就是我在服务器端(check_notifs.php)所拥有的:

header("Content-type: application/json;charset=utf-8", false);

if(/* user is logged in */){
    $_CHECKED = $user->get("last_checked");

    /* update the last time they checked their notifications */
    $_TIMESTAMP = time();
    $user->update("last_checked", $_TIMESTAMP);

    /* give the server a temporary break */
    sleep(1);

    /* here I am endlessly looping until the conditions are met, sleeping every
    *  iteration to reduce server stress */
    $_PDO = new PDO('...', '...', '...');
    while(true){
        $query = $_PDO->prepare("SELECT COUNT(*) as total FROM table WHERE timestamp > :unix");
        if($query->execute([":unix" => $_CHECKED])){
            if($query->rowCount()){
                /* check if the database has updated and if it has, break out of
                *  the while loop */
                $total = $query->fetchAll(PDO::FETCH_OBJ)[0]->total;
                if($total > 0){
                    echo json_encode(["total" => $total]);
                    break;
                }
                /* if the database hasn't updated, sleep the script for one second,
                *  then check if it has updated again */
                sleep(1);
                continue;
            }
        }
    }
}   

/* for good measure */
exit;

我已经阅读了有关 NodeJS 以及建议用于长期轮询的各种其他框架的信息,但不幸的是,它们目前对我来说是遥不可及的,因此我不得不使用 PHP < / strong>。我还环顾四周,看看Apache配置中的任何内容是否都可以解决我的问题,但是我只遇到了How do you increase the max number of concurrent connections in Apache?,考虑到我仍然可以使用我的内容,提及的内容似乎并不是问题所在相同服务器上的其他localhost网站。

我对如何解决此问题感到非常困惑,因此,我们非常感谢所有帮助,
干嘛。

1 个答案:

答案 0 :(得分:1)

实际情况是php正在等待此脚本结束(锁定)以将下一个请求提供给同一文件。

As you can read here

  
      
  • 某处有一些锁-例如,如果两个请求来自同一客户端,而您正在使用,则会发生这种情况   PHP中基于文件的会话:执行脚本时,   会话被“锁定”,这意味着服务器/客户端将不得不等待   直到第一个请求完成(并且文件已解锁)   使用该文件为第二个用户打开会话。
  •   
  • 请求来自相同的客户端和相同的浏览器;在这种情况下,即使存在   没有任何服务器端会产生这种行为。
  •   
  • MaxClients当前活动的进程不止这些-之前请参阅Apache手册中的报价。
  •   

实际上某处有某种锁。您需要检查正在发生什么锁定。也许while($getwpi = $getwpicon->fetch_assoc()){ $year = date('Y', strtotime($getwpi['datum'])); $getwpi['datum'] = $year; // update your field $wpi[] = $getwpi; // add to the result array } 拥有锁,您必须在$_PDO之前将其关闭,以保持解锁状态,直到发出下一个请求为止。

您可以尝试举起sleep(1)和/或申请this answer

  

执行MaxClients(或cakephp中的相应功能)以在ajax端点的开头关闭会话。