Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple AJAX requests delay each other

I have a long polling request on my page. The script on the server side is set to timeout after 20 seconds.

So, when the long polling is "idling", and the user presses another button, the sending of that new request is delayed until the previous script times out.

I can't see anything wrong with the code on jQuery side. Why is the onclick-event delayed?

function poll()
{
$.ajax({
    url: "/xhr/poll/1",
    data: {
        user_id: app.user.id
    },
    type: "POST",
    dataType: "JSON",
    success: pollComplete,
    error: function(response) {
        console.log(response);
    }
});
}

function pollComplete()
{
    poll();
}

function joinRoom(user_id)
{
$.ajax({
    url: "/xhr/room/join",
    dataType: "JSON",
    type: "POST",
    data: {
        user_id: app.user.id,
        room_id: room.id
    }
});
}

<button id="join" onclick="javascript:joinRoom(2);">Join</button>

############ PHP Controller on /xhr/poll

$time = time();
while ((time() - $time) < 20)
{
    $updates = $db->getNewStuff();

    foreach ($updates->getResult() as $update)
        $response[] = $update->getResponse();

    if (!empty($response))
        return $response;
    else
        usleep(1 * 1000000);

    return 'no-updates';
}

Could the "usleep" be the problem?

XHR Screenshot

like image 466
F.P Avatar asked Aug 01 '11 19:08

F.P


1 Answers

If you use sessions in the AJAX handling functions, you may run in to an issue where the server is maintaining session data on disk. If so, the data may be locked by the first request, so each subsequent request ends up waiting for the session data file to be available before it proceeds. In effect, this makes asynchronous calls block one another, you end up with linear responses to the requests in chronological order - synchronous. (here's a reference article)

A PHP-specific solution is to use session_write_close (docs) to close out the session as soon as you don't need it any more. This allows other subsequent requests to proceed because the session data will be "unlocked". Other server-side languages manage sessions in different ways, but this is usually something you can manage or control through some mechanism.

Managing sessions can have some pitfalls. If you call session_write_close (or otherwise end a session) right before you return a response, then you aren't going to do yourself any favors because the session would have been unlocked as soon as the response was sent. Thus, it needs to be called as early as possible.In smaller projects, this isn't so bad because you often have a php script that just handles the request and dumps a response, but if you have a larger framework and your request handler is only a part of it, you'll have to explore a more top-level solution to non-blocking session usage so your subcomponents are not closing a session that the framework expects is still open.

One route is to go with database session. There are pros and cons to this solution which are beyond the scope of this answer - check Google for exhaustive discussion for your particular server-side language. Another route is to use a function that opens a session, adds a variable, then closes it. You risk race conditions with this solution, but here's a rough outline using PHP as an example:

function get_session_var($key, $default=null) {
    if (strlen($key) < 1)
        return null;
    if (!isset($_SESSION) || !is_array($_SESSION)) {
        session_start();
        session_write_close();
    }
    if (array_key_exists($key, $_SESSION))
        return $_SESSION[$key];
    return $default;
}
function set_session_var($key, $value=null) {
    if (strlen($key) < 1)
        return false;
    if ($value === null && array_key_exists($key, $_SESSION)) {
        session_start();
        unset($_SESSION[$key]);
    } elseif ($value != null) {
        session_start();
        $_SESSION[$key] = $value;
    } else {
        return false;
    }
    session_write_close();
    return true;
}
like image 72
Chris Baker Avatar answered Nov 04 '22 16:11

Chris Baker