Question

I have designed a coding platform just like Spoj and Codeforces for competitions to be organised in my college on LAN.

I have used long polling there so that any announcements from the Admin can be broadcasted to all users with a JavaScript alert message. When anything is posted on the forum then the admin also gets a notification.

But for just 16 users (including the 1 Admin) accessing the site, the server went down showing too many sql connections. I restarted my laptop (server) and it continued for a while, then again went down; giving the same error message as before.

When I removed both long-poll processes everything continued smoothly.

Server-side code for long-poll:

include 'dbconnect.php';

$old_ann_id = $_GET['old_ann_id']; 
$resultann = mysqli_query($con,"SELECT cmntid FROM announcements ORDER BY cmntid DESC       LIMIT 1");

while($rowann = mysqli_fetch_array($resultann)){
    $last_ann_id = $rowann['cmntid']; 
}

while($last_ann_id <= $old_ann_id){
    usleep(10000000);
    clearstatcache();

    $resultann = mysqli_query($con,"SELECT cmntid FROM announcements ORDER BY cmntid DESC LIMIT 1");
    while($rowann = mysqli_fetch_array($resultann)){
        $last_ann_id = $rowann['cmntid']; 
    }
}

$response = array();
$response['msg'] = 'new';
$response['old_ann_id'] = $last_ann_id;
$resultann = mysqli_query($con, "Select announcements from announcements where    cmntid = $last_ann_id");
while($rowann = mysqli_fetch_array($resultann)){
     $response['announcement'] = $rowann['announcements'];
}

echo json_encode($response);
Was it helpful?

Solution

Max connections is defined. Think the default is 100 or 151 connections depending on the version of MySQL. You can see the value in "Server variables and settings" in phpmyadmin (or directly by executing *show variables like "max_connections";* ).

If that is set to something very low (say 10) and you have (say) 15 users you will hit the limit rapidly. You are giving each long polling script its own connection, and that connection is probably sitting open until that long polling script ends. You could likely reduce this by having the script disconnect after each time it checks the database, then reconnect the next time it checks (ie, if your long polling script checks the db every 5 seconds you probably have well over 4.5 seconds of that 5 seconds currently where there is a connection to the db but where the connection is not being used)

However you could have a larger number of connections, but if you trigger the ajax polling multiple times per user, each could have several simultaneous connections. This is probably quite easy to do with a minor bug in your javascript.

Possibly worse if you are using a persistent connections you might leave connections open after the user has left the page that calls the long polling script.

EDIT - update based on your script.

Note I am not sure exactly what your dbconnect.php include is doing. I might be possible to easily call a connect / disconnect function in that include, but I have just put it in this example code as using the mysqlu_close and mysqli_connect functions.

<?php
include 'dbconnect.php';
$old_ann_id = $_GET['old_ann_id']; 
$resultann = mysqli_query($con,"SELECT MAX(cmntid) FROM announcements");
if($rowann = mysqli_fetch_array($resultann))
{
    $last_ann_id = $rowann['cmntid']; 
}
$timeout = 0;
while($last_ann_id <=$old_ann_id and $timeout < 6)
{
    $timeout++;
    mysqli_close($con);
    usleep(10000000);
    clearstatcache();
    $con = mysqli_connect("myhost","myuser","mypassw","mybd");
    $resultann = mysqli_query($con,"SELECT MAX(cmntid) FROM announcements");
    if($rowann = mysqli_fetch_array($resultann))
    {
        $last_ann_id = $rowann['cmntid']; 
    }
}
if ($last_ann_id >$old_ann_id)
{
    $response = array();
    $response['msg'] = 'new';
    $response['old_ann_id'] = $last_ann_id;
    $resultann=mysqli_query($con,"SELECT cmntid, announcements FROM announcements WHERE    cmntid>$old_ann_id ORDER BY cmntid");
    while($rowann = mysqli_fetch_array($resultann))
    {
         $response['announcement'][]=$rowann['announcements'];
         $response['old_ann_id'] = $rowann['cmntid'];
    }
    mysqli_close($con);
    echo json_encode($response);
}
else
{
    echo "No annoucements - resubmit";
}
?>

I have added a count to the main loop. But it will drop out of the loop whether anything is found once it has executed 6 times. This way even if someone leaves the page the script will only be running for a short time afterwards (max a minute). You will have to amend you javascript to catch this and resubmit the ajax call.

Also I have changed the announcement in the response to be an array. This way if there are several announcements while the script is running all will be brought back.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top