Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep trying to talk to server when the Internet is down

So my application is exchanging request/responses with a server (no problems), until the internet connection dies for a couple of seconds, then comes back. Then a code like this:

response = (HttpWebResponse)request.GetResponse();

will throw an exception, with a status like ReceiveFailure, ConnectFailure, KeepAliveFailure etc.

Now, it's quite important that if the internet connection comes back, I am able to continue communicating with the server, otherwise I'd have to start again from the beginning and that will take a long time.

How would you go about resuming this communication when the internet is back?

At the moment, I keep on checking for a possibility to communicate with the server, until it is possible (at least theoretically). My code attempt looks like this:

try
{
    response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
    // We have a problem receiving stuff from the server. 
    // We'll keep on trying for a while
    if (ex.Status == WebExceptionStatus.ReceiveFailure || 
        ex.Status == WebExceptionStatus.ConnectFailure || 
        ex.Status == WebExceptionStatus.KeepAliveFailure)
    {
        bool stillNoInternet = true;

        // keep trying to talk to the server
        while (stillNoInternet)
        {
            try
            {
                response = (HttpWebResponse)request.GetResponse();
                stillNoInternet = false;
            }
            catch
            {
                stillNoInternet = true;
            }
        }
    }
}

However, the problem is that the second try-catch statement keeps throwing an exception even when the internet is back.

What am I doing wrong? Is there another way to go about fixing this?

Thanks!

like image 419
Alex Avatar asked Aug 05 '11 12:08

Alex


1 Answers

You should recreate the request each time, and you should execute the retries in a loop with a wait between each retry. The wait time should progressively increase with each failure.

E.g.

ExecuteWithRetry (delegate {
    // retry the whole connection attempt each time
    HttpWebRequest request = ...;
    response = request.GetResponse();
    ...
});

private void ExecuteWithRetry (Action action) {
    // Use a maximum count, we don't want to loop forever
    // Alternativly, you could use a time based limit (eg, try for up to 30 minutes)
    const int maxRetries = 5;

    bool done = false;
    int attempts = 0;

    while (!done) {
        attempts++;
        try {
            action ();
            done = true;
        } catch (WebException ex) {
            if (!IsRetryable (ex)) {
                throw;
            }

            if (attempts >= maxRetries) {
                throw;
            }

            // Back-off and retry a bit later, don't just repeatedly hammer the connection
            Thread.Sleep (SleepTime (attempts));
        }
    }
}

private int SleepTime (int retryCount) {
    // I just made these times up, chose correct values depending on your needs.
    // Progressivly increase the wait time as the number of attempts increase.
    switch (retryCount) {
        case 0: return 0;
        case 1: return 1000;
        case 2: return 5000;
        case 3: return 10000;
        default: return 30000;
    }
}

private bool IsRetryable (WebException ex) {
    return
        ex.Status == WebExceptionStatus.ReceiveFailure ||
        ex.Status == WebExceptionStatus.ConnectFailure ||
        ex.Status == WebExceptionStatus.KeepAliveFailure;
}
like image 199
Chris Chilvers Avatar answered Sep 28 '22 08:09

Chris Chilvers