一种方法是标准的异步方法,如下所示:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
我测试了两个实现,一个使用等待,另一个使用 .Wait()
这两个实现完全不相同,因为相同的测试失败了await版本而不是Wait()版本。
此方法的目标是“执行输入函数返回的任务,并通过执行相同的函数重试直到它工作”(如果达到一定次数的尝试,则自动停止的限制)。
这有效:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(t =>
{
// Wait for the recursive call to complete
AutoRetryHandlerAsync_Worker(taskToRun).Wait();
});
// Stop
return;
}
}
这个(使用async t =>
和使用await
代替t =>
以及使用.Wait()
根本不起作用,因为递归调用的结果在最终return;
执行之前不等待:
private static async Task AutoRetryHandlerAsync_Worker(Func<Task<bool>> taskToRun,...)
{
try {
await taskToRun();
}
catch(Exception)
{
// Execute later, and wait the result to complete
await Task.Delay(currentDelayMs).ContinueWith(async t =>
{
// Wait for the recursive call to complete
await AutoRetryHandlerAsync_Worker(taskToRun);
});
// Stop
return;
}
}
我试图理解为什么这个简单的改变会改变一切,当它应该做同样的事情时:等待ContinueWith完成。
如果我提取由ContinueWith
方法运行的任务,我确实看到ContinueWith函数的状态在内部等待返回完成之前传递给“ranToCompletion”。
为什么呢?是不是应该等待它?
public static void Main(string[] args)
{
long o = 0;
Task.Run(async () =>
{
// #1 await
await Task.Delay(1000).ContinueWith(async t =>
{
// #2 await
await Task.Delay(1000).ContinueWith(t2 => {
o = 10;
});
});
var hello = o;
});
Task.Delay(10000).Wait();
}
为什么在o = 10之前达到var hello = o;
?
#1等待是否应该在执行继续之前挂起?
答案 0 :(得分:6)
lambda语法模糊了ContinueWith( async void ...)的事实。
不等待异步void方法,并且它们抛出的任何错误都将被忽略。
对于你的基本问题,无论如何都不是在捕获内重试。太多了,抓住块应该很简单。并且直截了当地重试所有异常类型也是非常可疑的。你应该知道哪些错误可以保证重试,其余的通过。
简单易懂:
while (count++ < N)
{
try
{
MainAction();
break;
}
catch(MoreSpecificException ex) { /* Log or Ignore */ }
Delay();
}