簡體   English   中英

C#中具有超時功能的通用異步重試

[英]Generic async Retry with Timeout function in C#

我有幾百個調用各種外部API,我希望將其包裝在一個能夠重試和處理超時的通用異步函數中。

基本上,我認為我需要實現類似這個函數調用的東西:

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

如何定義此類重試功能? 另外,我如何從同步代碼中調用此功能,因為我的調用大量存在於同步方法中?

不要重新發明輪子。 只需使用支持您正在討論的場景的Polly ,以及各種重試場景和斷路器等高級模式。

這是他們的文檔的異步示例:

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

如何定義此類重試功能?

  1. 安裝Polly
  2. 定義策略並使用它。
  3. 利潤。

這樣的事情應該有效:

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文章,了解您可以嘗試的各種黑客攻擊。 但是,保持異步代碼異步和同步代碼同步會更好。

如果你仍然對如何在沒有政策的情況下這樣做感到好奇,那將是這樣的:

/// 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;
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM