Search code examples
phpmysqlpollingserver-sent-events

Server-Sent Events from PHP polling mySQL


A back-office periodically needs to sent data to clients connected to a web application. Here is the script I have setup:

<?php
header("Content-Type: text/event-stream\n\n");
header('Cache-Control: no-cache');

flush();
ob_flush();

require_once('connect.php');
//connect to the database
$mysql = mysql_connect($hostname, $username, $password) or die ('cannot reach database');
$db = mysql_select_db($database) or die ("this is not a valid database");
mysql_query("SET NAMES 'utf8'", $mysql);

$query = mysql_query("SELECT * FROM `clientEvents` ORDER BY id DESC LIMIT 1") or die(mysql_error());
    $row = mysql_fetch_array($query);
    $index = $row["id"];
    echo $index;

loop($index);

function loop($index){
while (1)
{
    ob_implicit_flush(true);
    $buffer = str_repeat(" ", 4096);
    echo $buffer."\n";

// Every second, look for new question.

$query = mysql_query("SELECT * FROM `clientEvents` WHERE id>$index ORDER BY id DESC LIMIT 1") or die(mysql_error());
$row = mysql_fetch_array($query);
if(mysql_num_rows($query)>0)
{
    if($row["type"]=="pushCustomQuestion"){
     pushCustomQuestion($row["data"],$row["id"]);
     break;
    }
    else if($row["type"]=="pushGameTimeEvent"){
     pushGameTimeEvent($row["data"],$row["id"]);
     break;
    }
}
sleep(3);
}

function pushGameTimeEvent($id,$index) {
    //echo "id for game event:".$id;
    $result = mysql_fetch_array(mysql_query("SELECT * FROM game_events WHERE id = $id LIMIT 1"));

    //$num_results = mysql_num_rows($result); 

    echo "event: new_game_event\n";
    echo 'data: {   "id": "' . $result['id'] . '",' 
                    .'"match_id": "' . $result['match_id'] . '",' 
                    .'"minute": "' . $result['minute'] . '",' 
                    .'"event_id": "' . $result['event_id'] . '",' 
                    .'"event_name": "' . $result['event_description'] . '",' 
                    .'"player_name": "' . $result['player1_name']. '",' 
                    .'"player2_name": "' . $result['player2_name'] . '",'
                    .'"which_half": "' . $result['which_half'] . '",'
                    .'"team_logo": "' . $result['team_logo'] . '"}';
    echo "\n\n";
    ob_flush();
    flush();
    sleep(10);
    loop($index);
}

Everything seems to work OK up until seven clients load the web application where everything hogs. Is there something wrong with the script as it is?

It seems to me that the way I'm doing it is counterintuitive since I'm polling the database in order to send a new event. Is there some other better way to trigger the event from the back- office application?

Thanks for any help.


Solution

  • It likely has to do with a limit imposed by Apache on the number of people whom can be connected like this at a time.

    Here is a great long polling tutorial and is a bit different from what you have setup: http://elikirk.com/2012/04/17/php-ajax-long-polling-comet-demonstration/

    But if you wish to scale this, long polling is not the best solution for realtime 'pushing'.

    I suggest taking a look at node.js and sockets.io as these technologies are specifically for this. The downside is that node.js is essentially its own server that runs javascript, so you will have to abandon php. But there are workarounds where you can bridge node.js and php via CURL.