Search code examples
javascriptajaxrecursionxmlhttprequest

Why do repeated ajax requests in a recursive function cause an error?


I have a field in a database which is initially set to 0 but may be set to 1 by other users of the site at any time. I want to create a javascript which waits until the field is set to 1.

To do this, I created the file load-variable.php, which loads and returns the field from the database. I then wrote a javascript function which loads this file using ajax and waits for a result.

If the result is still 0, the same function is called again, with a 500ms delay created by the window.setTimeout function. If the result is 1, a different function called continueScript is called which executes the next part of the program.

Here is the code:

function loadVariable() {

    xhr = new XMLHttpRequest();
    xhr.open('GET', 'load-variable.php', true);
    xhr.send();

    xhr.onload = function() {

        if (xhr.responseText == '0') {
            window.setTimeout(loadVariable, 500);
        } else {
            continueScript();
        } 
    }   
}

If the database field changes to 1 within about 15 seconds of the function first being called, this function works very nicely.

However, if it takes longer than that, an error eventually occurs (last time I tested, this happened after the function had been called 28 times, which is roughly after 15 seconds of waiting).

My browser is safari (could the problem be browser-specific?) and I get the following error:

Safari can't open the page. The error is: “The operation couldn't be completed. Protocol error ” (NSPOSIXErrorDomain:100)

Am I doing something wrong? Are repeated ajax requests in a function that calls itself the correct way to keep data live, or is my method incorrect and thus causing the problem?

Thanks in advance for your advice!


Update 04/04/20 (1)

The problem is really very strange! After this error has been caused, it takes about 10–20 minutes before I can visit my site again.

Even if I try and load another page which has nothing to do with this program and does not use ajax, the same error message still comes up, and I have to wait for the site to 'recover' before I can continue.


Update 04/04/20 (2)

Here is the content of load-variable.php, which reads data from a mysql database.

<?php

// Database details (I've obviously not included them here)
$servername = "";
$username = "";
$password = "";
$dbname = "";

// Create connection
$conn = new mysqli($servername, $username, $password, $dbname);

$sql = "SELECT Variable FROM Table WHERE Id='1';";
$query = mysqli_query($conn, $sql);

echo(mysqli_fetch_array($query)[0]);


exit();

?>

Update 04/04/20 (3)

I've now tested this problem in chrome, and there was also an error. Here, the message was:

Your IP address was blocked due to suspicious behaviour.

To me it now appears that it's my server which thinks that my behaviour is suspicious and therefore blocks the me for a period of time. Are repeated requests for the same field in a database are seen as 'suspicious'?


Solution

  • It's really difficult to tell where your problem might lie.

    • What database are you using? Do you have a database lock that gets generated at some point?
    • What does you php look like? Is their recursive logic in your php file itself?
    • What does your call stack look like? Can you trace the results of your database calls and pinpoint the moment your exception occurs?

    Having said that, this isn't really a problem with ajax, but more the underlying implementation. Let's take a step back and ask ourselves what we're trying to achieve. You want to watch your database for changes and trigger and update when a change occurs. Sounds like you need to use the observable pattern here. A really good example of how to implement this is to look at how the Redis library does things.

    As to the error you're seeing, let's take a look at how Safari works.

    Safari supports a bunch of HTTP protocols. When a networking library attempts to transmit data via Safari, Safari says "I support the following protocols, x and y". When you initially attempt to fetch data from your database, it's done so using HTTP protocol x. At some point, your database server says to Safari, "Hey, I speak the newer protocol y, talk to me in protocol y instead", and an upgrade header is sent.

    When Safari sees this, it interprets it as "upgrade to network protocol y", but it can't since it already supports this network protocol, and that's when your error message pops up.

    Would you see this error with a different browser? Probably not, since other browsers tend to be more lenient with this use case.

    Does this error have anything to do with your ajax requests? Maybe, but this isn't where you should be looking to solve the issue of "I need to observe changes to my database and update my front-end accordingly". Change your implementation to use something like mysql-events.

    I know I'm avoiding giving you a "direct" fix to your issue, but there are so many contributing factors to a solution that's best for your code base, and me saying do this or that exactly as I tell you to would more likely make things worse for you in the long run. So instead, I hope I can point you in the right direction.