C#中具有超时function的通用异步重试

我有几百个对各种外部API的调用,我希望将其包装在能够进行重试和处理超时的通用异步函数中。

基本上,我认为我需要实现类似这样的函数调用:

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

如何定义此类重试function? 另外,如何从同步代码中调用此function,因为我的调用大量存在于同步方法中?

不要重新发明轮子。 只需使用支持您正在讨论的场景的Polly ,以及各种重试场景和断路器等高级模式。

这是他们的文档中的异步示例:

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

如何定义此类重试function?

  1. 安装Polly
  2. 定义策略并使用它。
  3. 利润。

像这样的东西应该工作:

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

另外,如何从同步代码中调用此function,因为我的调用大量存在于同步方法中?

这是一个完全不同的问题。 阻止异步代码总是有陷阱。 没有适用于任何Func解决方案。 如果您必须这样做,请参阅我的MSDN文章,了解您可以尝试的各种黑客攻击。 但是,保持异步代码异步和同步代码同步会更好。

如果您仍然对如何在没有Policy的情况下这样做感到好奇,那么它将是这样的:

 /// Untested code static class Retry { public static async Task Run(Func> 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 Run(Func> 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; } }