4

I have a server and create a web interface for it, if a user presses the reboot button on the page, then the user is redirected to reboot.php where he is supposed to see a spinner gif till the server is reachable again and the server is getting rebooted via shell execute. If the server is reachable then i need to redirect to main.php

So i created the following function. The function starts with a timeout of 5 seconds, because otherwise it would instantly load main.php because the reboot command takes it's time.

reboot.php

    $ret = false;

    test();

    function test()
    {
        setTimeout
        (
            function()
            {
                 $ret = ping("www.google.de");
                 if ($ret === false)
                 {
                     test();
                 }
                 else
                 {
                     window.location.href = "main.php";
                 }
            },
            3000
        );
    }

    function ping(url)
    {
        $.ajax
        (
            {
                url: url,
                success: function(result)
                {
                    alert('reply');
                    return true;
                },     
                error: function(result)
                {
                    alert('timeout/error');
                    return false;
                }
            }
        );
    }

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

    <div class="col-lg-6 col-lg-offset-3" id="mydiv">
        <div class="mydiv_inhalt">
            <h2>Rebooting...</h2>
            <p>This can take about 2 minutes.</p>
            <center>
                <div class="waiting" id="waiting" style="margin-top:30px; margin-left: 0px;">
                    <center><img class="loading_table" src="http://www.securenet.com/sites/default/files/spinner.gif" alt="spinner gif"></center>
                </div>
            </center>
        </div>
    </div>

ajax.php

$cmd        = filter_input(INPUT_POST, "cmd");
if ( isset( $cmd ) && $cmd == "check_online_status" )
{
    echo "true";
}

In my ajax.php i simply return "true" if the call was successful. However, my logic does not work, it seems that my code only tries to make one call to my ajax.php and then never tries again and i get net::ERR_CONNECTION_REFUSED in the console.

I put many alerts into my code, but they are not executed, so i guess it does not try to call ajax.php a second time after getting net::ERR_CONNECTION_REFUSED.

My only idea would be to wait enough time and then redirect to main.php, but this is not a good solution because luck is needed, what if the time was not enough etc.

Black
  • 18,150
  • 39
  • 158
  • 271

8 Answers8

7

Let's summarize the issues in your code:

  • you need to use setInterval to execute the function every x seconds
  • the ajax request is asynchronous, and it should stay like that. You can't expect a return value from the callback, instead, you should act in the callback

The resulting code is way simpler:

var pingUrl = "www.google.de";
var targetUrl = "main.php";
setInterval(ping, 3000);

function ping() {
    $.ajax({
        url: pingUrl,
        success: function(result) {
            window.location.href = targetUrl;
        }
    });
}
Alessandro
  • 1,443
  • 9
  • 18
  • setTimeout(function(){ setInterval(ping, 2000); },8000); would first wait for 10 seconds, and then ping the server every 2 seconds. – diynevala Mar 18 '16 at 11:57
1

@EdwardBlack fisrt you have to assing .gif image to image tag with id then in that image tag you to pass style="display:none"

<img id="imgid" src="" style="display:none">

function ping(url) {

        $.ajax({
              
                url: url,
                beforeSend : function(){
                   $('#imgid').css({'display':'block'}); //or 
                   $('#imgid').css('display', 'block');   // any one
                }, 
                success: function() {
                    alert('reply');
                    return true;
                },     
                error: function() {
                    alert('timeout/error');
                    return false;
                }
            });
    }

Vikash Jha
  • 67
  • 1
  • 7
0

If the server is rebooting, usually you'll need some kind of failover IP or at least a caching proxy in front of the application server (in this case, OpenERP) to tell the user that it's down. Otherwise, while the server is offline, you'll just get a generic browser error message returned to the client, like "server not found" or similar.

In short, the best way to do this is to have another physical/virtual server sitting in front of the application server that is "always" up (or a cluster of servers that are rebooted independently), so that you always have something resolving the domain name or can fail over to a backup if the primary is down due to crashes or reboots.

Hope it helps

Solid-Snake
  • 147
  • 1
  • 2
  • 13
  • 2
    OP want a JS page client side that'll be loaded before the reboot, and do a ping-like request on the server to get an answer before triggered the JE redirect... – Blag Mar 15 '16 at 10:10
  • Yes, im sorry if i did not expressed me correctly but yes this is my goal. Blag is right. – Black Mar 15 '16 at 10:33
0

setTimeout runs the function only once

you can use setInterval instead of setTimeout

Kwan
  • 237
  • 1
  • 3
  • 8
  • if you read the code you will see that he does a recursive setup of setTimeout – Soren Mar 18 '16 at 08:20
  • @Soren The beginning version of this question, it does not conatins any recursive. – Kwan Mar 18 '16 at 08:31
  • 1
    read it again: `function test() { .... if( === false) test(); ...` -- so he is attempting to recursively setup a new timeout using function `test` if the condition is false.... – Soren Mar 18 '16 at 08:36
  • Revisions 2: http://stackoverflow.com/revisions/695f40c4-9fae-41ad-8a7a-820604a41500/view-source – Kwan Mar 18 '16 at 08:39
  • I see your point... It is bad style on the OPs part to change the question in such a fundamental way – Soren Mar 18 '16 at 08:57
0

This code should work. What I have done:

  • Use setInterval instead of setTimeout to execute the ping-function every x seconds.
  • The $.post function is executed asynchronously (the ajax request). That means that you cannot use a while loop as you did (except you set jQuery to make the call synchronously).
  • Please don't use Umlaute (äöü) in your code. Nothing good can come of it.

var timeoutCounter = 0;

var interval = setInterval(function() {
    ping(10);
}, 5000);

function ping(maxTimeouts) {
    $.post(
        'ajax.php',
        { cmd: "check_online_status" },
        function(data, status) {
            if (status == "success") {
                window.location.href = 'main.php';
                clearInterval(interval);
            } else { 
                timeoutCounter++;

                if (timeoutCounter >= maxTimeouts) {
                    alert("Max Timeouts ("+ maxTimeouts + ") exceeded!");
                    clearInterval(interval);
                }
            }
        }
    );  
}
sjkm
  • 3,887
  • 2
  • 25
  • 43
0

This may help as it's the closest to a ping you can do with JS : https://github.com/jdfreder/pingjs

Use the fallback as a recursive lunch-again part, and be careful to not redirect to quick in the first part.

Blag
  • 5,818
  • 2
  • 22
  • 45
0

Your ping function needs to be synchronous: param async: false in ajax request.

With the async request you made, you never enter the condition if ($ret === false), so the recursive call can't be made.

Also, returning a value in the successor error callbacks does not make your ping function returning the value you want.

You have to rewrite your pingfunction like this:

function ping(url)
{
    var ret = false;
    $.ajax
    (
        {
            async: false,
            url: url,
            success: function(result)
            {
                alert('reply');
                ret = true;
            },     
            error: function(result)
            {
                alert('timeout/error');
                ret = false;
            }
        }
    );
    return ret;
}
ADreNaLiNe-DJ
  • 4,787
  • 3
  • 26
  • 35
  • Yes i tested it. If the ajax call fails, you are in `error` callback. When ajax ends correctly (server has finiched rebooting), you are in `success` callback so it returns `true` – ADreNaLiNe-DJ Mar 18 '16 at 09:15
0

You cannot return synchronously from the ping the way you do -- the return value is alway undefined in the test function if you check the value with a debugger. The reason is that $.ajax is not a synchronous call.

You should not (bad style) rely on synchronous apis when building javascript, so need to consider how to do the same using an async pattern.

For further reading, look at this question: How do I return the response from an asynchronous call?

Rewrite your code to use a async pattern, something like this;

$ret = false;

function rebooted(){ console.log("Reboot complete")};
test( rebooted );

function test(okcb)
{
    setTimeout
    (
        function()
        {
             ping("www.google.de",
                 function(){ $ret=true; okcb(); },
                 function(){ test(okcb);}
             );
        },
        3000
    );
}

function ping(url, yeah, nooo)
{
    $.ajax
    (
        {
            url: url,
            success: function(result)
            {
                console.log('reply');
                yeah();
            },     
            error: function(result)
            {
                console.log('timeout/error');
                nooo();
            }
        }
    );
}
Community
  • 1
  • 1
Soren
  • 14,402
  • 4
  • 41
  • 67