Keep trying to talk to server when the Internet is down
Asked Answered
R

3

6

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!

Rubstone answered 5/8, 2011 at 12:26 Comment(3)
Not an answer to your question, but if your connection goes down for a longish time, you've no really good way to kill this at present...Rent
The server also has a timeout of 5 minutes, so if the connection really goes down for more than 5 minutes, then that's the way to kill it.Rubstone
why don't you set up a timer to test for a connection every 10 minutes then restart whatever it was doing? or maybe everytime there's a connectfailure increase the wait time by a minute.Sleepless
C
17

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;
}
Cristoforo answered 5/8, 2011 at 12:47 Comment(0)
H
1

I think what you are trying to do is this:

HttpWebResponse RetryGetResponse(HttpWebRequest request)
{
    while (true)
    {
        try
        {
            return (HttpWebResponse)request.GetResponse();
        }
        catch (WebException ex)
        {
            if (ex.Status != WebExceptionStatus.ReceiveFailure &&
                ex.Status != WebExceptionStatus.ConnectFailure &&
                ex.Status != WebExceptionStatus.KeepAliveFailure)
            {
                throw;
            }
        }
    }
}

When you want to retry something on failure then instead of thinking of this as something that you want to do when something fails, think of it instead as looping until you succeed. (or a failure that you don't want to retry on). The above will keep on retrying until either a response is returned or a different exception is thrown.

It would also be a good idea to introduce a maximum retry limit of some sort (for example stop retrying after 1 hour).

Hydrogenolysis answered 5/8, 2011 at 12:48 Comment(0)
G
0

If it's still doing it when you get the connection back - then my guess is that it's simply returning the same result again.

You might want to to try recreating the request anew each time, other than that I don't see much wrong with the code or logic. Apart from the fact that you're forever blocking this thread. But then that might be okay if this is, in itself, a worker thread.

Gallinule answered 5/8, 2011 at 12:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.