C# 怎么更简单的使用Polly

Polly是一个C#实现的弹性瞬时错误处理库,它可以帮助我们做一些容错模式处理,比如:

  • 超时与重试(Timeout and Retry)
  • 熔断器(Circuit Breaker)
  • 舱壁隔离(Bulkhead Isolation)
  • 回退(Fallback)

使用也是非常简单的,比如:

// Retry multiple times, calling an action on each retry 
// with the current exception and retry count
Policy
.Handle<SomeExceptionType>()
.Retry(3, onRetry: (exception, retryCount) =>
{
// Add logic to be executed before each retry, such as logging
});

但是每个地方我们都得这样写,个人还是不喜,
那么怎么简化呢?
当然是使用 Norns.Urd 这些AOP框架封装我们常用的东西做成 Attribute 啦

 

如何实现简化呢?

我们来尝试将 Retry功能 做成 RetryAttribute吧

1.安装 AOP 框架

自己写多累呀,用现成的多好呀

dotnet add package Norns.Urd

2.编写 Retry InterceptorAttribute

public class RetryAttribute : AbstractInterceptorAttribute
{
private readonly int retryCount;

public RetryAttribute(int retryCount)
{
this.retryCount = retryCount;
}

public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next)
{
await Policy.Handle<Exception>()
.RetryAsync(retryCount)
.ExecuteAsync(() => next(context));
}
}

3.考虑到 async 和 sync 在Polly 有差异,那么我们兼容一下吧

public class RetryAttribute : AbstractInterceptorAttribute
{
private readonly int retryCount;

public RetryAttribute(int retryCount)
{
this.retryCount = retryCount;
}

public override void Invoke(AspectContext context, AspectDelegate next)
{
Policy.Handle<Exception>()
.Retry(retryCount)
.Execute(() => next(context));
}

public override async Task InvokeAsync(AspectContext context, AsyncAspectDelegate next)
{
await Policy.Handle<Exception>()
.RetryAsync(retryCount)
.ExecuteAsync(() => next(context));
}
}

4.我们来做个测试吧

public class RetryTest
{
public class DoRetryTest
{
public int Count { get; set; }

[Retry(2)] // 使用 Retry
public virtual void Do()
{
if (Count < 50)
{
 Count++; // 每调用一次就加1
 throw new FieldAccessException();
}
}
}

public DoRetryTest Mock()
{
return new ServiceCollection()
.AddTransient<DoRetryTest>()
.ConfigureAop()
.BuildServiceProvider()
.GetRequiredService<DoRetryTest>();
}

[Fact]
public void RetryWhenSync()
{
var sut = Mock();
Assert.Throws<FieldAccessException>(() => sut.Do());
Assert.Equal(3, sut.Count); //我们期望调用总共 3 次
}
}

是的,就是这样,我们可以在任何地方使用 RetryAttribute

 

当然,一些常见的方法已经封装在了 Norns.Urd.Extensions.Polly

这里通过Norns.Urd将Polly的各种功能集成为更加方便使用的功能

如何启用 Norns.Urd + Polly, 只需使用EnablePolly()

如:

new ServiceCollection()
.AddTransient<DoTimeoutTest>()
.ConfigureAop(i => i.EnablePolly())

TimeoutAttribute

[Timeout(seconds: 1)] // timeout 1 seconds, when timeout will throw TimeoutRejectedException
double Wait(double seconds);

[Timeout(timeSpan: "00:00:00.100")] // timeout 100 milliseconds, only work on async method when no CancellationToken
async Task<double> WaitAsync(double seconds, CancellationToken cancellationToken = default);

[Timeout(timeSpan: "00:00:01")] // timeout 1 seconds, but no work on async method when no CancellationToken
async Task<double> NoCancellationTokenWaitAsync(double seconds);

RetryAttribute

[Retry(retryCount: 2, ExceptionType = typeof(AccessViolationException))] // retry 2 times when if throw Exception
void Do()

CircuitBreakerAttribute

[CircuitBreaker(exceptionsAllowedBeforeBreaking: 3, durationOfBreak: "00:00:01")] 
//or
[AdvancedCircuitBreaker(failureThreshold: 0.1, samplingDuration: "00:00:01", minimumThroughput: 3, durationOfBreak: "00:00:01")]
void Do()

BulkheadAttribute

[Bulkhead(maxParallelization: 5, maxQueuingActions: 10)]
void Do()

有关 Norns.Urd, 大家可以查看 https://fs7744.github.io/Norns.Urd/zh-cn/index.html

以上就是c# 如何更简单的使用Polly的详细内容,更多关于c# 使用Polly的资料请关注编程宝库其它相关文章!

 0. 前言首先立马解释一波为啥会有这样一篇伪标题的Demo随笔呢?不是本人有知识误区,或者要误人子弟因为大家都知道emit写出来的都是同步方法,不可能await,至少现在这么多年来没有提 ...