12

I have problem with two simultaneous AJAX requests running. I have a PHP script which is exporting data to XSLX. This operation take a lot of time, so I'm trying to show progress to the user. I'm using AJAX and database approach. Actually, I'm pretty sure it used to work but I can't figure out why, it's no longer working in any browser. Did something change in new browsers?

$(document).ready(function() {

        $("#progressbar").progressbar();

        $.ajax({
            type: "POST",
            url: "{$BASE_URL}/export/project/ajaxExport",
            data: "type={$type}&progressUid={$progressUid}" // unique ID I'm using to track progress from database
        }).done(function(data) {
            $("#progressbar-box").hide();
            clearInterval(progressInterval);
        });

        progressInterval = setInterval(function() {
            $.ajax({
                type: "POST",
                url: "{$BASE_URL}/ajax/progressShow",
                data: "statusId={$progressUid}" // the same uinque ID
            }).done(function(data) {
                data = jQuery.parseJSON(data);
                $("#progressbar").progressbar({ value: parseInt(data.progress) });
                if (data.title) { $("#progressbar-title").text(data.title); }
            });
        }, 500);

    });
  • the progress is correctly updating in database
  • the JS timer is trying to get the progress, I can see it in console, but all these request are loading the whole duration of the first script, as soon as the script ends, these ajax progress calls are loaded

So, why is the second AJAX call waiting for the first one to finish?

halfer
  • 19,824
  • 17
  • 99
  • 186
filip.karas
  • 596
  • 2
  • 11
  • 27
  • 3
    Some PHP web server configurations only allow one connection per session to run concurrently. So, if you are using sessions, try an experiment in a page where you (a) start a session, and then (b) sleep for 60 seconds. Then try loading a number of instances of this page in the same browser - they may well load one after the other. – halfer Mar 28 '13 at 16:05
  • Have you updated the jQuery version recently? – Joshua - Pendo Mar 28 '13 at 16:05
  • 1
    Also, in general, more than one AJAX op is not best practice, since it wastes time over excess HTTP calls. Can you merge them into one, and return several results back in a JSON string? – halfer Mar 28 '13 at 16:08
  • 3
    If you're using server-side sessions, PHP will by default lock the session file while a request is active, meaning you cannot have more than one outstanding request active at any one time. – Marc B Mar 28 '13 at 16:25
  • Marc B you're right! It was the session issue. I was using codeigniter session library, but I changed it to native session library recently and I did not realised this could be the issue. Thank You. You can post it as answer so I can mark it as accepted. – filip.karas Mar 28 '13 at 17:03
  • [Run multiple AJAX requests in parallel with jQuery][1] [1]: http://stackoverflow.com/questions/1060539/parallel-asynchronous-ajax-requests-using-jquery/22317997#22317997 – srikanth_yarram Mar 11 '14 at 06:27

6 Answers6

39

Sounds like a session blocking issue

By default PHP writes its session data to a file. When you initiate a session with session_start() it opens the file for writing and locks it to prevent concurrent edits. That means that for each request going through a PHP script using a session has to wait for the first session to be done with the file.

The way to fix this is to change PHP sessions to not use files or to close your session write like so:

<?php
    session_start(); // starting the session

    $_SESSION['foo'] = 'bar'; // Write data to the session if you want to

    session_write_close(); // close the session file and release the lock

    echo $_SESSION['foo']; // You can still read from the session.
chrislondon
  • 12,487
  • 5
  • 26
  • 65
  • Ay carumba. Not a fan of PHP sessions, but developing using Symfony which makes exhaustive use of them. Makes sense but would've never guessed. Good help! – eggmatters Oct 19 '16 at 19:47
3

After a bit of hair-pulling, I found one other way that these non-parallel AJAX requests can happen, totally independent of PHP session-handling... So I'm posting it here just for anyone getting here through Google with the same problem.

XDebug can cause this, and I wouldn't be surprised if Zend Debugger could too.

In my case, I had:

  • XDebug installed on my local LAMP stack
  • xdebug.remote_autostart enabled
  • My IDE accepting inbound debugger-connections, even though no breakpoints were active

This caused all my AJAX tests to run sequentially, no matter what. In retrospect it makes a lot of sense (from the standpoint of debugging things) to force sequential processing, but I simply hadn't noticed that my IDE was still interacting behind-the-scenes.

After telling the IDE to stop listening entirely, parallel runs resumed and I was able to reproduce the race-condition I had been looking for.

Darien
  • 3,482
  • 19
  • 35
2

Be aware, that session_write_close()(answer of chrislondon) may not resolve the problem if you have enabled output buffering (default in PHP 7+). You have to set output_buffering = Off in php.ini, otherwise session won't be closed correctly.

Eje
  • 354
  • 4
  • 8
0

When working with APIs, you sometimes need to issue multiple AJAX requests to different endpoints. Instead of waiting for one request to complete before issuing the next, you can speed things up with jQuery by requesting the data in parallel, by using jQuery's $.when() function:

Run multiple AJAX requests in parallel

Community
  • 1
  • 1
srikanth_yarram
  • 957
  • 9
  • 16
0

a.php generates a main HTML page that contains two simultaneous AJAX calls to b.php and c.php. In order for b.php and c.php to share session variables, the session variables must exist BEFORE the first AJAX call. Provided this is true, a.php and b.php can change the value of the session variables and see each other's values. Therefore, create the session variables with a.php while generating the HTML page. At least that's how it works with Rogers shared web hosting.

Eje
  • 354
  • 4
  • 8
Doug
  • 1
-1

You could also set

async: true,
daniel langer
  • 1,855
  • 2
  • 17
  • 20