1

We have a display board that needs to update every second. The AJAX call to the server triggers a stored proc that is a pretty simple SELECT statement and it takes only milliseconds to execute.

Originally, from time to time because of network latency (or sunspots, or who knows what) this AJAX process would (occasionally, rarely) time out. By tweaking how we handle the timer and by setting the timeout to 0, we have it so it's now running stable and the timeout never happens... yet.

That being said, I'm still nervous that a timeout could still happen. And IF happens, the goal is that it would just keep going. Basically, ignore the timeout and just try again... forever. Nothing like MaxError, or RetryLimit, or TryCount, etc.

Here's what I have now:

setTimeout(function run() {
    // When the timer elapses, get the data from the server
    GetData();
    setTimeout(run, _refreshRate);
}, 1000);


function GetData() {
    //console.log("Attempting to obtain the data...");
    jQuery.ajax({
        url: "something.ashx",
        type: "GET",
        contentType: 'application/json; charset=utf-8',
        success: function(resultData) {
            //console.log("Got the data.");
            ParseJson(resultData);
            // show the last refresh date and time
            $('#refreshTime').html(GetDateTime());
        },
        error : function(xhr, textStatus, errorThrown) {
            if (textStatus == 'timeout') {
                //console.log("Timeout occured while getting data from the server.  Trying again.");
                // If a timeout happens, DON'T STOP. Just keep going forever.
                $.ajax(this);
                return;
            }
         },
         timeout: 0,
    });
}

Everything inside of ParseJson(resultData); works great. No issues there. And The timer is setup (I believe) so that it will wait until one GetData() is done before it tries to start another.

I believe that by setting the timeout to 0 that it means "don't ever time out."

My question is this:

Am I correctly handling the error for a timeout? I am using the selected answer in this thread as my guide:

What's the best way to retry an AJAX request on failure using jQuery?

But I don't need a retryLimit limit.

I've also looked at these threads:

How to make the Ajax call again in case Time out error occurs

ajax timeout callback function

I think I've boiled all the info down to a simple solution, but I would like some peer review. Is there a better way to do this?

Mackan
  • 6,200
  • 2
  • 25
  • 45
Casey Crookston
  • 13,016
  • 24
  • 107
  • 193
  • From what it looks like, it should already be happening. Your `run` function is set to execute every 1 second. And it's set outside the scope of your ajax call, so it shouldn't matter if your ajax call times out or not. Have you tried debugging this? – Matt Spinks Dec 11 '17 at 15:08
  • Every second puts heavy load on server. You should really use websockets for doing this – charlietfl Dec 11 '17 at 15:21
  • @MattSpinks - yes, a lot. After much trial and error we got to this point and now it seems to be stable. By that I mean, it no longer times out. At least, we let it run for hours and tested it heavily and it never timed out, which before it was doing every couple of minutes. So I THINK we are good. Mostly I'm just looking for any peer suggestions on how to improve, or if there are an potential gotchya's in this code. – Casey Crookston Dec 11 '17 at 15:27
  • @charlietfl, thank you! I really appreciate the idea. I confess I had not thought of websockets, but that might be a better solution. The good news is that the SP that is run is seriously tiny. We ran all kinds of tests on it inside SQL Query Analyzer and Profiler, and the load on the *database* server is almost non-existent. So, question: How would websockets help lower the load on the web server? – Casey Crookston Dec 11 '17 at 15:30
  • Ok great. I would probably change your mechanism to poll from inside your `success` and `error` functions, instead of in your `run` function. The reason for this is that, if there is any kind of network error, then your code won't be blindly sending off more requests, even though the last request hasn't returned yet. – Matt Spinks Dec 11 '17 at 15:31
  • @MattSpinks, I'm not sure i follow. "... change your mechanism to poll from inside your success and error functions, instead of in your run function." – Casey Crookston Dec 11 '17 at 15:37
  • Difference is significant. Constant open connection vs having to process a new request and run it through all the routing, app initialization and compiling etc. Easy to web search comparison of the two approaches – charlietfl Dec 11 '17 at 15:40
  • Well, right now, your `run` function is getting executed every second, regardless of the response you get back. Just move this line: `setTimeout(run, _refreshRate);` to both the `success` function and the `error` function. Or, better yet, implement the `complete` function in your ajax call, and run it from there (executes whether it was successful or not). This essentially makes your polling synchronous with your responses. – Matt Spinks Dec 11 '17 at 15:40

2 Answers2

6

I'd prefer a solution that only queued a new call when the current had completed. something like..

function poll() {
  setTimeout(function () {
     GetData();
  }, 1000);
}

function GetData() {
    jQuery.ajax({
        url: "something.ashx",
        type: "GET",
        contentType: 'application/json; charset=utf-8',
        success: function(resultData) {
            //...
        },
        error : function(xhr, textStatus, errorThrown) {
            //...
        },
        complete: function() {
           poll();
        },
        timeout: 0,
    });
}

poll();

This way your calls will not risk overlapping anyway.

Mackan
  • 6,200
  • 2
  • 25
  • 45
1
function GetData() {
    //console.log("Attempting to obtain the data...");
    jQuery.ajax({
        url: "something.ashx",
        type: "GET",
        contentType: 'application/json; charset=utf-8',
        success: function(resultData) {
            //console.log("Got the data.");
            ParseJson(resultData);
            // show the last refresh date and time
            $('#refreshTime').html(GetDateTime());
        },
        error : function(xhr, textStatus, errorThrown) {
            if (textStatus == 'timeout') {
                //console.log("Timeout occured while getting data from the server.  Trying again.");
                // If a timeout happens, DON'T STOP. Just keep going forever.
                $.ajax(this);
                return;
            }
         },
         timeout: 0,
    });
}

var myInterval = setInterval(getData, 1000)
// if you want to stop it elsewhere:
// clearInterval(myInterval)

Instead of timeout you could use setInterval

Thomas
  • 2,431
  • 17
  • 22
  • 1
    You could, but this doesn't solve anything in the current design. Calls would still risk getting queued up, and now you have an interval to handle instead of a fire-and-forget timeout. What would be the upside? :) – Mackan Dec 11 '17 at 15:59
  • In contrast to your solution i can garantee that the request is made every second. Your solution didn't take the request time in account. But at the end you are right. For his needs your solution is better suited. So i leave my answer for other usecases and mark your answer as helpful. ;) – Thomas Dec 11 '17 at 16:15
  • Just to point out obvious of what was said, this can stack up requests if they take longer than the timeout to return data - which may have some use case somewhere – Mark Schultheiss Oct 06 '20 at 14:28