4

When posting simple data to a plain PHP script using jQuery $.ajax({...}) multiple requests are handled in parallel. When doing to same with a Symfony 2.8 controller as a target, the request is handled synchronously. Why is this?

Plain HTML and PHP setup

// Plain PHP file: /testscript.php
<?php 
    sleep($_POST['time']);
    echo $_POST['id'];


// Plain HTML file: /testpage.html
<html>
<head>
    <script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
</head>
<body>
Click here:
<div id='testbtn' style="background-color: #abc">Click</div>

 <script>
    $(document).ready(function() {
        var start = new Date().getTime();
        var count = 1;

        $("#testbtn").click(function() {
            var time = new Date().getTime();
            console.log('Click at '+count+':' + (time - start));

            $.ajax({
                url : '/testscript.php',
                type : "post",
                data : {'time':3, 'id':count},
                async: true,
                context : this,
                success : function(data) {
                    var end = new Date().getTime();
                    console.log('Click Success: ' + data + "  -  " + (end - start));
                }
            });

            count++;
        });


        $.ajax({
            url : '/testscript.php',
            type : "post",
            data : {'time':10, 'id':0},
            async: true,
            context : this,
            success : function(data) {
                var end = new Date().getTime();
                console.log('Auto Success: ' + data + "  -  " + (end - start));
            }
        });

        console.log('Ajax fired');
    });
</script>

</body>
</html>    

Symfony Setup

// Controller Action to handle /sym_testscript.php
public function testScriptAction(Request $request) {
    sleep($request->get('time'));
    return new Response($request->get('id'), Response::HTTP_OK);
}


// Controller Action to handle /sym_testpage.php
public function testPageAction() {
    return $this->render('MyBundle::sym_testpage.html.twig');
}   


// Twig-Template for /sym_testpage.html
...exactly the same HTML code as above. Twig is only used to insert URL
...
$.ajax({
    url : '{{ path('sym_testscript') }}',
    ...

The page /testpage.html calls /testscript.php when being loaded with a sleep-value of 10 seconds. When clicking the Button a few times the page load waterfall looks something like this:

1: ========================================   // initial call of testscript.php
2:     ============                           // testscript.php called by 1 click
3:      ============                          // testscript.php called by 2 click
4:         ============                       // testscript.php called by 3 click

Each click on the Button immediately calls the testscript.php which is then executed in parallel to the initial call and other button calls. So each click-call runs 3 seconds.

When using the Symfony version instead, the waterfall looks like this:

1: ========================================   // initial call of testscript.php
2:     ====================================================                           
3:      ================================================================                          
4:         ============================================================================

Again, each button click immediately calls the /sym_testscript.php. But now the calls are handled one after the other. Thus the total runtime is not 10 seconds but 19 = 10 + 3 + 3 + 3...

When using the sym_testscript.php within the plain HTML file as the target, the result is the same. Thus the problem seems to be within the Symfony controller...

Why is this? Why are the ajax-calls not handled in parallel when using the Symfony solution?

Sumesh TG
  • 2,557
  • 2
  • 15
  • 29
Andrei Herford
  • 17,570
  • 19
  • 91
  • 225
  • 4
    Are you running your symfony application with PHP built-in server (like using `php app/console server:run`) ? If so, this server can only handle one request at a time. Try using Apache or Nginx, it should work as expected – LP154 Aug 27 '18 at 11:34
  • No, this is the result when calling the pages within the browser. The result is the same when running `Symfony` on my local machine (XAMPP) and on the shared hosting Webspace of my provider – Andrei Herford Aug 27 '18 at 11:49
  • Could you give us the virtual host configuration for both setups ? – LP154 Aug 27 '18 at 11:51
  • 1
    Is the symfony script using a session? PHP sessions are locked by the request so multiple requests using the same session will run sequentially. – jeroen Aug 27 '18 at 12:00
  • 1
    @jeroen Thank you very much for your hint regarding sessions. This seems to be indeed the problem! After adding `$request->getSession()->save()` to the controller, it behaves as expected (parallel instead of sequentially). If it would be an answer I would accept it :-) – Andrei Herford Aug 27 '18 at 12:21

1 Answers1

4

As soon as you start a session in php, php will lock it and subsequent requests will have to wait until the session is available again.

So if your symfony script uses sessions, you can only execute 1 request at a time using that session while the session is open.

Disabling sessions (if that even is an option...) or closing it when you don't need it any more will allow parallel requests.

jeroen
  • 91,079
  • 21
  • 114
  • 132
  • Depends if you are using native PHP-sessions or a custom handler, https://symfony.com/doc/current/components/http_foundation/session_configuration.html – Andreas Bergström Aug 27 '18 at 14:36
  • @AndreasBergström That may be true, but as far as I can see that only refers to where the data is stored, not how the session itself is managed. If you have any references to the docs that specifically refer to session blocking, I would be very interested to see them :-) – jeroen Aug 27 '18 at 14:57
  • True, I have been away from server-rendered applications too long and only had token-based sessions in my mind. So yes, I supose PHPs native sessions are still used. :) – Andreas Bergström Aug 27 '18 at 16:13
  • I found this other answer useful: https://stackoverflow.com/a/47912230/1094673 – Bob Aug 25 '22 at 09:28