Polly 重试除特定条件外的所有异常

m1n*_*keh 5 c# polly

Polly 中是否有一种方法可以重试除指定的异常之外的所有异常.. 例如:

var p = Policy
    .Handle<HttpListenerException>(e => !(e.NativeErrorCode == 1))
    .Or<Exception>()
    .RetryAsync();
Run Code Online (Sandbox Code Playgroud)

在这里,我选择了一个略显做作的情况,我会想不是在重试NativeErrorCode == 1

我最初希望这会在 1 以外的任何值以及由.Or<Exception>()..处理的任何其他异常时重试。

实际发生的是什么,即使它被排除在上面,.Or<Exception>也会捕获NativeErrorCode == 1?我认为..

我考虑过的一种选择,但没有经过测试......(没有错误检查;p)

var p = Policy
    .Handle<Exception>(e => SomethingMoreComplex(e) == true)
    .RetryAsync();

private bool SomethingMoreComplex(Exception e)
{
    if (e is HttpListenerException t)
    {
        if (t.NativeErrorCode == 1) return false;
    }

    return true;
}
Run Code Online (Sandbox Code Playgroud)

那是线程安全的吗?:|

Pet*_*ala 4

如果您查看Policy.HandleSyntax.cs文件,您可以看到这些Handle<T>方法是如何定义的:

public partial class Policy
{
    public static PolicyBuilder Handle<TException>() where TException : Exception
        => new PolicyBuilder(exception => exception is TException ? exception : null);

    public static PolicyBuilder Handle<TException>(Func<TException, bool> exceptionPredicate) where TException : Exception
        => new PolicyBuilder(exception => exception is TException texception && exceptionPredicate(texception) ? exception : null);
        
    ...
}

public partial class Policy<TResult>
{
    public static PolicyBuilder<TResult> Handle<TException>() where TException : Exception
        => new PolicyBuilder<TResult>(exception => exception is TException ? exception : null);

    public static PolicyBuilder<TResult> Handle<TException>(Func<TException, bool> exceptionPredicate) where TException : Exception
        => new PolicyBuilder<TResult>(exception => exception is TException texception && exceptionPredicate(texception) ? exception : null);
            
    ...
}
Run Code Online (Sandbox Code Playgroud)
  • 所有方法都依赖于该类PolicyBuilder,该类具有内部 ctor
    • 因此,我们不能在自定义代码中使用它。
  • 另请注意,该类Policy没有公共 ctor
    • 因此,我们无法创建实例Policy,这就是为什么为类创建扩展方法没有意义Policy

这是克服这些限制的一种方法:

public static class PolicyExt
{
    public static PolicyBuilder HandleExcept<TException>() where TException : Exception
        => Policy.Handle((Exception exception) => exception is TException is false);

    public static PolicyBuilder HandleExcept<TException>(Func<TException, bool> exceptionPredicate) where TException : Exception
        => Policy.Handle((Exception exception) => exception is TException is false || exception is TException texception && !exceptionPredicate(texception));
}

public static class PolicyExt<TResult>
{
    public static PolicyBuilder<TResult> Handle<TException>() where TException : Exception
        => Policy<TResult>.Handle((Exception exception) => exception is TException is false);

    public static PolicyBuilder<TResult> Handle<TException>(Func<TException, bool> exceptionPredicate) where TException : Exception
        => Policy<TResult>.Handle((Exception exception) => exception is TException is false || exception is TException texception && !exceptionPredicate(texception));
}
Run Code Online (Sandbox Code Playgroud)

最后这是一个快速测试:

var policy = PolicyExt.HandleExcept<Exception>(ex => ex is NotSupportedException)
    .WaitAndRetry(2, _ => TimeSpan.FromSeconds(2));

//Or just:
//var policy = PolicyExt.HandleExcept<NotSupportedException>()
//    .WaitAndRetry(2, _ => TimeSpan.FromSeconds(2));

policy.Execute(() =>
{
    Console.WriteLine("Have been called");
    throw new NotSupportedException();
});
Run Code Online (Sandbox Code Playgroud)

输出:

Have been called
Unhandled exception. System.NotSupportedException: Specified method is not supported.
Run Code Online (Sandbox Code Playgroud)
  • 所以,万一NotSupportedException重试逻辑没有被触发。
  • 但是如果我们针对以下委托执行策略:
Have been called
Unhandled exception. System.NotSupportedException: Specified method is not supported.
Run Code Online (Sandbox Code Playgroud)

然后输出将如下:

Have been called
Have been called
Have been called
Unhandled exception. System.Exception: Custom
Run Code Online (Sandbox Code Playgroud)

因此,重试被触发。