写在前面

Polly 是一个 .NET 弹性和瞬态故障处理库,允许开发人员以 Fluent 和线程安全的方式来实现重试、断路、超时、隔离和回退策略。

Polly 的七种策略介绍

重试(Retry): 当出现故障时自动进行重试

断路(Circuit-breaker):当系统遇到严重问题时,快速回馈失败比让用户/调用者等待要好,限制系统出错的体量,有助于系统恢复。

超时(Timeout):当系统超过一定时间的等待,我们就几乎可以判断不可能会有成功的结果,直接去干别的事情。

隔离(Bulkhead Isolation):当系统的一处出现故障时,可能促发多个失败的调用,很容易耗尽主机的资源(如 CPU)。下游系统出现故障可能导致上游的故障的调用,甚至可能蔓延到导致系统崩溃。所以要将可控的操作限制在一个固定大小的资源池中,以隔离有潜在可能相互影响的操作。

回退(Fallback):有些错误无法避免,就要有备用的方案。这个就像浏览器不支持一些新的 CSS 特性就要额外引用一个 polyfill 一样。一般情况,当无法避免的错误发生时,我们要有一个合理的返回来代替失败。

缓存(Cache):一般我们会把频繁使用且不会怎么变化的资源缓存起来,以提高系统的响应速度。如果不对缓存资源的调用进行封装,那么我们调用的时候就要先判断缓存中有没有这个资源,有的话就从缓存返回,否则就从资源存储的地方(比如数据库)获取后缓存起来,再返回,而且有时还要考虑缓存过期和如何更新缓存的问题。Polly 提供了缓存策略的支持,使得问题变得简单。

策略包(Policy Wrap):一种操作会有多种不同的故障,而不同的故障处理需要不同的策略。这些不同的策略必须包在一起,作为一个策略包,才能应用在同一种操作上。这就是文章开头说的 Polly 的弹性,即各种不同的策略能够灵活地组合起来。

通过NuGet安装Polly类库:

官方项目地址: https://github.com/App-vNext/Polly 

代码实现

    /// <summary>
    /// FallBack => 当出现故障,则进入降级动作
    /// </summary>
    public static void Case1()
    {
        ISyncPolicy policy = Policy.Handle<ArgumentException>()
            .Fallback(() =>
            {
                Console.WriteLine("Error occured");
            });
 
        policy.Execute(() =>
        {
            Console.WriteLine("Job Start");
 
            throw new ArgumentException("Hello Polly!");
 
            Console.WriteLine("Job End");
        });
    }
 
    /// <summary>
    /// Retry => 重试
    /// </summary>
    public static void Case2()
    {
        ISyncPolicy policy = Policy.Handle<Exception>().Retry(3);
 
        try
        {
            policy.Execute(() =>
            {
                Console.WriteLine("Job Start");
                if (DateTime.Now.Second % 10 != 0)
                {
                    throw new Exception("Special error occured");
                }
                Console.WriteLine("Job End");
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine("There's one unhandled exception : " + ex.Message);
        }
    }
 
    /// <summary>
    /// CircuitBreaker => 短路保护
    /// </summary>
    public static void Case3()
    {
        // Stop for 10s after retry 6 times
        ISyncPolicy policy = Policy.Handle<Exception>()
            .CircuitBreaker(6, TimeSpan.FromSeconds(10));
 
        while (true)
        {
            try
            {
                policy.Execute(() =>
                {
                    Console.WriteLine("Job Start");
                    throw new Exception("Special error occured");
                    Console.WriteLine("Job End");
                });
            }
            catch (Exception ex)
            {
                Console.WriteLine("There's one unhandled exception : " + ex.Message);
            }
 
            Thread.Sleep(500);
        }
    }
 
    /// <summary>
    /// Timeout 与 Wrap => Wrap是指策略封装,可以把多个ISyncPolicy合并到一起执行。Timeout则是指超时处理,但是超时策略一般不能直接使用,而是其其他策略封装到一起使用。
    /// </summary>
    public static void Case4()
    {
        try
        {
            ISyncPolicy policyException = Policy.Handle<TimeoutRejectedException>()
                .Fallback(() =>
                {
                    Console.WriteLine("Fallback");
                });
            ISyncPolicy policyTimeout = Policy.Timeout(3, Polly.Timeout.TimeoutStrategy.Pessimistic);
            ISyncPolicy mainPolicy = Policy.Wrap(policyTimeout, policyException);
            mainPolicy.Execute(() =>
            {
                Console.WriteLine("Job Start...");
                Thread.Sleep(5000);
                throw new Exception(); 
                Console.WriteLine("Job End...");
            });
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Unhandled exception : {ex.GetType()} : {ex.Message}");
        }
    }
 
    /// <summary>
    /// 异步方法
    /// </summary>
    public static async void Case5()
    {
        var policy = Policy<byte[]>.Handle<Exception>()
            .FallbackAsync(async c =>
            {
                Console.WriteLine("Executed Error!");
                return new byte[0];
            }, async r =>
            {
                Console.WriteLine(r.Exception);
            });
 
        policy.WrapAsync(Policy.TimeoutAsync(5, TimeoutStrategy.Pessimistic,
         async (context, timespan, task) =>
         {
             Console.WriteLine("Timeout!");
         }));
 
        var bytes = await policy.ExecuteAsync(async () =>
        {
            Console.WriteLine("Start Job");
            HttpClient httpClient = new HttpClient();
            var result = await httpClient.GetByteArrayAsync("https://img-blog.csdnimg.cn/img_convert/50f2b9069f40b88ea8348492d56abb87.png");
            Console.WriteLine("Finish Job");
 
            return result;
        });
 
        Console.WriteLine($"Length of bytes : {bytes.Length}");
    }

调用示例

Case1:

Case2: 

Case3:

到此这篇关于.NET中弹性和瞬时处理库Polly的使用详解的文章就介绍到这了,更多相关.NET Polly内容请搜索本站以前的文章或继续浏览下面的相关文章希望大家以后多多支持本站!

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部