HiveBrain v1.2.0
Get Started
← Back to all entries
debugcsharpMinor

Retry loop for asynchronous HTTP requests

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
asynchronousloophttpforrequestsretry

Problem

I've got a method that needs to PUT data to a web API. Sometimes the connection fails, so I needed a way to do retries, but if the retries fail, I still need to capture the exception and re-throw it.

I've got something that I "believe" is working, but I've got a stupid throw at the end. Is there a better, more concise way to do this when working with async tasks?

private const int TotalNumberOfAttempts = 10;

public static async Task PutWithRetriesAsync(string url,
    HttpContent content,
    AuthenticationHeaderValue authenticationHeaderValue,
    MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue)
{
    var numberOfAttempts = 0;
    ExceptionDispatchInfo capturedException;

    do
    {
        try
        {
            return await PutAsync(url, content, authenticationHeaderValue, mediaTypeWithQualityHeaderValue);
        }
        catch (AggregateException ex)
        {
            capturedException = ExceptionDispatchInfo.Capture(ex);
            numberOfAttempts++;
        }
    } while (numberOfAttempts < TotalNumberOfAttempts);

    if (capturedException != null)
    {
        capturedException.Throw();
    }
    throw new Exception("That will never be thrown");
}

Solution

I would rewrite your code into a while (true) loop, that can only be exited using the return in your try or using a throw; inside a condition in your catch:

while (true)
{
    try
    {
        return await PutAsync(url, content, authenticationHeaderValue, mediaTypeWithQualityHeaderValue);
    }
    catch
    {
        numberOfAttempts++;
        if (numberOfAttempts >= TotalNumberOfAttempts)
            throw;
    }
}


This way, you don't need ExceptionDispatchInfo or the useless (but required by the compiler) throw at the end.

I also changed catch (AggregateException ex) to catch all exceptions, because await usually doesn't throw AggregateException (unlike task.Wait() or task.Result).

Code Snippets

while (true)
{
    try
    {
        return await PutAsync(url, content, authenticationHeaderValue, mediaTypeWithQualityHeaderValue);
    }
    catch
    {
        numberOfAttempts++;
        if (numberOfAttempts >= TotalNumberOfAttempts)
            throw;
    }
}

Context

StackExchange Code Review Q#59829, answer score: 3

Revisions (0)

No revisions yet.