写点什么

如何更简单的使用 Polly

用户头像
八苦-瞿昙
关注
发布于: 2020 年 12 月 13 日

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 countPolicy    .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
复制代码


  1. 编写 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)); } }
复制代码


  1. 考虑到 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)); } }
复制代码


  1. 我们来做个测试吧

    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 TimeoutRejectedExceptiondouble Wait(double seconds);
[Timeout(timeSpan: "00:00:00.100")] // timeout 100 milliseconds, only work on async method when no CancellationTokenasync Task<double> WaitAsync(double seconds, CancellationToken cancellationToken = default);
[Timeout(timeSpan: "00:00:01")] // timeout 1 seconds, but no work on async method when no CancellationTokenasync Task<double> NoCancellationTokenWaitAsync(double seconds);
复制代码


RetryAttribute


[Retry(retryCount: 2, ExceptionType = typeof(AccessViolationException))]  // retry 2 times when if throw Exceptionvoid 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


发布于: 2020 年 12 月 13 日阅读数: 36
用户头像

八苦-瞿昙

关注

一个假和尚,不懂人情世故。 2018.11.23 加入

会点点技术,能写些代码,只爱静静。 g hub: https://github.com/fs7744 黑历史:https://www.cnblogs.com/fs7744

评论

发布
暂无评论
如何更简单的使用Polly