Polly RetryForever 没有重试

Polly RetryForever isn't retrying

我正在尝试检查一个简单的 RetryForever of Polly

class Program
{
    public static void Main()
    {
           
        int i = 0;
        var _retryPolicy = Policy
       .Handle<Exception>()
       .RetryForever();

        _retryPolicy.Execute(async () =>
        {
            Console.WriteLine(i);
            i++;
            int.Parse("something");
        });

        Console.ReadLine();
    }
}   

你可以看到我创建了一个变量i来跟踪执行次数

异常结果: 打印 i = 0、1、2 等

实际结果: 打印 i = 0

我检查了你的代码,你是对的,它在 0 处停止。

但是当我删除 async 关键字时(你在这里没有任何异步操作)代码运行正确。

所以,试试这个:

using Polly;

int i = 0;
var _retryPolicy = Policy
  .Handle<Exception>()
  .RetryForever();

_retryPolicy.Execute(() =>
{
  Console.WriteLine(i);
  i++;
  int.Parse("something");
  return Task.CompletedTask;
});

我可能会迟到,但让我分享我的智慧。


当你定义一个策略时,你必须预先知道你想要修饰一个sync或一个异步 method/function.

同步方法的重试策略

Policy
  .Handle<Exception>()
  .RetryForever();

异步方法的重试策略

Policy
  .Handle<Exception>()
  .RetryForeverAsync();
  • 在前一种情况下,您有一个 Execute 方法可以预期
    • 一个Action(一个没有return值的方法)
    • Func<TResult>(一种方法 TResult 输入 return 值)
    • 还有许多其他重载
  • 在后一种情况下,您有一个 ExecuteAsync 方法可以预期
    • a Func<Task>(没有 return 值的异步方法)
    • Func<Task<TResult>>(具有 TResult 类型 return 值的异步方法)
    • 还有许多其他重载

同步功能的重试策略

Policy<int>
  .Handle<Exception>()
  .RetryForever();

异步函数的重试策略

Policy<int>
  .Handle<Exception>()
  .RetryForeverAsync();

在这些情况下,您要修饰的代码应该 return 和 int.

因此 Execute 预期 Func<int> 代表

policy.Execute(() => { ... return 42; });

并且 ExecuteAsync 预期 Func<Task<int>> 代表

await policy.Execute(async () => { ... return Task.FromResult(42); });

返回您的代码

由于您在策略定义期间没有对 return 类型做出任何限制,因此您可以传递一个 Func,其中 return 是一个 TaskExecute(async () => { ...});).

因此,您的 Execute return 是一个 Task,它不是 awaited。

让我们拭目以待

await _retryPolicy.Execute(async () =>
{
    Console.WriteLine(i);
    i++;
    int.Parse("something");
});

如果你 await returned Task 那么它会抛出一个 FormatException。 但是该异常是由 Execute 委托之外的 await 抛出的。因此,它将不会触发重试。

修复选项 A

_retryPolicy.Execute(() =>
{
    Console.WriteLine(i);
    i++;
    int.Parse("something");
});

通过删除 async,您的委托将是一个 Action,它会抛出 FormatException,从而触发重试策略。

修正选项 B

var _retryPolicy = Policy<int>
  .Handle<Exception>()
  .RetryForeverAsync();

await _retryPolicy.ExecuteAsync(async () =>
{
    Console.WriteLine(i);
    i++;
    int.Parse("something");
});

如果您为异步方法定义了策略并且您 await ExecuteAsync 那么它也将起作用。为什么?因为 ExecuteAsync awaits the provided delegate 即使您没有将委托定义为 async

await _retryPolicy.ExecuteAsync(() =>
{
    Console.WriteLine(i);
    i++;
    int.Parse("something");
    return Task.CompletedTask; //This code is never reached
});