.NET5微服务示例-Polly熔断与降级

什么是Polly:https://www.cnblogs.com/lwqlun/p/8119856.html

策略示例:https://www.cnblogs.com/TianFang/archive/2018/01/06.html

控制台简单示例(需Nuget安装Polly包)

using Polly;
using Polly.Timeout;
using System;
using System.Threading;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            //Method1();
            //string s2 = Method2();
            //Method3();
            //Method4();
            //Method5();
            //Method6();
            Console.ReadKey();
        }

        /// <summary>
        /// 普通使用
        /// </summary>
        static void Method1()
        {
            //指定捕获ArgumentException异常,如果不是ArgumentException,那么Fallback就捕获不到
            Policy.Handle<ArgumentException>() 
                .Fallback(() =>
                {
                    Console.WriteLine("出现错误了");
                }, ex => //可以拿到Fallback的异常信息
                {
                    Console.WriteLine($"异常信息:{ex.Message}");
                })
                //执行业务操作
                .Execute(() =>
                {
                    Console.WriteLine("开始");
                    throw new ArgumentException("异常了!");
                    Console.WriteLine("结束");
                });
        }

        /// <summary>
        /// 带返回值
        /// </summary>
        static string Method2()
        {
            var policy = Policy<string>.Handle<ArgumentException>()
                .Fallback("Fallback的返回值");
            var result = policy.Execute(() =>
                {
                    //throw new ArgumentException("异常了!");
                    return "Execute的返回值";
                });
            //如果Execute中出现了ArgumentException异常,那么result将会得到Fallback的返回值
            return result;
        }

        /// <summary>
        /// 重试示例
        /// </summary>
        static void Method3()
        {
            Policy.Handle<ArgumentException>()
                //.Retry(3) //不填数字默认重试一次
                //.WaitAndRetry(3, i => TimeSpan.FromSeconds(1)) //重试3次,每次等待1秒后再重试
                .RetryForever() //不停重试
                .Execute(() =>
                {
                    Console.WriteLine("开始");
                    if (DateTime.Now.Second % 10 != 0)
                    {
                        throw new ArgumentException("异常了!");
                    }
                    Console.WriteLine("结束");
                });
        }

        /// <summary>
        /// 断路保护
        /// </summary>
        static void Method4()
        {
            var policy = Policy.Handle<ArgumentException>()
                .CircuitBreaker(2, TimeSpan.FromSeconds(5)); //连续出错2次后熔断5秒

            while (true)
            {
                try
                {
                    policy.Execute(() =>
                    {
                        Console.WriteLine("开始");
                        throw new ArgumentException("异常了!");
                        Console.WriteLine("结束");
                    });
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                }
                Thread.Sleep(1000);
            }
        }

        /// <summary>
        /// 策略封装-重试
        /// </summary>
        static void Method5()
        {
            var policyRetry = Policy.Handle<ArgumentException>().Retry(3);
            var policyFallback = Policy.Handle<ArgumentException>()
                .Fallback(()=>{
                    Console.WriteLine("Fallback");
                });
            //如果policyRetry重试3次后还有故障,就把故障抛给policyFallback处理
            var policy = policyFallback.Wrap(policyRetry);
            policy.Execute(() =>
            {
                Console.WriteLine("开始");
                throw new ArgumentException("异常了!");
                Console.WriteLine("结束");
            });
        }

        /// <summary>
        /// 策略封装-超时
        /// </summary>
        static void Method6()
        {
            //Pessimistic悲观的超时策略,通过其他方式保证超时(并返回给调用者)
            var policyTimeout = Policy.Timeout(3, TimeoutStrategy.Pessimistic);
            var policyFallback = Policy.Handle<TimeoutRejectedException>() //超时策略就是抛出这个异常的
                .Fallback(() => {
                    Console.WriteLine("Fallback");
                });
            var policy = policyFallback.Wrap(policyTimeout);
            policy.Execute(() =>
            {
                Console.WriteLine("开始");
                Thread.Sleep(5000); //模拟超时5秒
                Console.WriteLine("结束");
            });
        }
    }
}
View Code

接着这篇文章:.NET5微服务示例-Consul注册中心

1、SGZ.Framework下安装Nuget包“Microsoft.Extensions.Http.Polly”

2、Extentions文件夹下新增扩展类PollyServiceCollectionExtension

using Microsoft.Extensions.DependencyInjection;
using Polly;
using SGZ.Framework.Models;
using System;
using System.Net.Http;

namespace SGZ.Framework.Extentions
{
    public static class PollyServiceCollectionExtension
    {
        public static IServiceCollection AddPollyHttpClient(this IServiceCollection services, string name, PollyConfig config)
        {
            services.AddHttpClient(name)
                .AddPolicyHandler(
                    Policy<HttpResponseMessage>
                    .Handle<ExecutionRejectedException>() // 捕获所有的Polly异常
                    .FallbackAsync(config.httpResponseMessage)
                )
                .AddPolicyHandler( //熔断策略
                    Policy<HttpResponseMessage>
                    .Handle<Exception>()
                    .CircuitBreakerAsync(
                        config.CircuitBreakerOpenFallCount
                        , TimeSpan.FromSeconds(config.CircuitBreakerDownTime)
                    )
                )
                .AddPolicyHandler( //超时策略
                    Policy.TimeoutAsync<HttpResponseMessage>(config.TimeoutTime)
                ) 
                .AddPolicyHandler( //重试策略
                    Policy<HttpResponseMessage>
                    .Handle<Exception>()
                    .RetryAsync(config.RetryCount)
                )
                .AddPolicyHandler( //资源隔离
                    //保证每一个服务都是固定的线程,防止一个服务占用过多线程而影响其它服务
                    Policy.BulkheadAsync<HttpResponseMessage>(10, 100)
                );
            return services;
        }
    }
}

3、SGZ.AggregationService的Startup类,ConfigureServices方法增加各个服务的Polly配置

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();

    services.AddConsul(Configuration);

    services.AddLoadBalance();

    #region Polly相关
    services.AddPollyHttpClient("DepartmentService", new PollyConfig
    {
        RetryCount = 2,
        TimeoutTime = 10,
        CircuitBreakerDownTime = 10,
        CircuitBreakerOpenFallCount = 2,
        httpResponseMessage = new HttpResponseMessage
        {
            Content = new StringContent("系统正繁忙,请稍后重试"),
            StatusCode = HttpStatusCode.BadGateway
        }
    });

    services.AddPollyHttpClient("PersonnelService", new PollyConfig
    {
        RetryCount = 2,
        TimeoutTime = 10,
        CircuitBreakerDownTime = 10,
        CircuitBreakerOpenFallCount = 2,
        httpResponseMessage = new HttpResponseMessage
        {
            Content = new StringContent("系统正繁忙,请稍后重试"),
            StatusCode = HttpStatusCode.BadGateway
        }
    }); 
    #endregion

    services.AddServiceRequest();
}

4、运行方式也如上一篇文章那样执行

本文代码:https://files.cnblogs.com/files/shousiji/net5_polly.rar

原文地址:https://www.cnblogs.com/shousiji/p/15268215.html