Generic async Retry with timeout function in C #

I have hundreds of calls to various external APIs that I want to wrap up in a common asynchronous function that is able to perform retries and processing timeouts.

Basically, it seems to me that I need to implement something like this function call:

await Retry(()=>someFunctionAsync(doWorkParams, new CancellationToken()), retryCount, timeout);

How to define such a Retry function? Also, how do I call this function from the synchronization code since a ton of my calls are stored in synchronization methods?

+6
source share
3 answers

. Polly, , , , .

async :

await Policy
  .Handle<SqlException>(ex => ex.Number == 1205)
  .Or<ArgumentException>(ex => ex.ParamName == "example")
  .RetryAsync()
  .ExecuteAsync(() => DoSomethingAsync());
+8

​​ Retry?

- :

static async Task RetryAsync(Func<CancellationToken, Task> func, int retryCount, TimeSpan timeout)
{
  using (var cts = new CancellationTokenSource(timeout))
  {
    var policy = Policy.Handle<Exception>(ex => !(ex is OperationCanceledException))
        .RetryAsync(retryCount);
    await policy.ExecuteAsync(() => func(cts.Token)).ConfigureAwait(false);
  }
}

, , ?

. . , Func<Task>. . MSDN , , . , , .

+7

If you are still wondering how to do this without a policy, it would be something like this:

/// Untested code
static class Retry
{
    public static async Task<T> Run<T>(Func<CancellationToken, Task<T>> function, int retries, TimeSpan timeout)
    {
        Exception error = null;
        do
        {
            try
            {
                var cancellation = new CancellationTokenSource(timeout);
                return await function(cancellation.Token).ConfigureAwait(false);
            }
            catch (Exception ex)
            {
                error = ex;
            }

            retries--;
        }
        while (retries > 0);

        throw error;
    }

    public static async Task<T> Run<T>(Func<Task<T>> function, int retries, TimeSpan timeout)
    {
        Exception error = null;
        do
        {
            try
            {
                var timeoutTask = Task.Delay(timeout);
                var resultTask = function();

                await Task.WhenAny(resultTask, timeoutTask).ConfigureAwait(false);

                if (resultTask.Status == TaskStatus.RanToCompletion)
                    return resultTask.Result;
                else
                    error = new TimeoutException();
            }
            catch (Exception ex)
            {
                error = ex;
            }

            retries--;
        }
        while (retries > 0);

        throw error;
    }
}
+1
source

Source: https://habr.com/ru/post/1016220/


All Articles