.Net Core 之 Polly 策略
Polly 是一个 .NET 弹性和瞬态故障处理库,允许开发人员以流畅和线程安全的方式表达重试、断路器、超时、隔板隔离、速率限制和回退等策略。
查看源码或者一些基础用法点击了解详情, 如果想更深入的了解,点击进入官网。
polly提供的几种弹性策略:
普通用法
引用NuGet包:
Install-Package Polly
悲观超时(TimeoutStrategy.Pessimistic),依然会返回结果
int res = 0; var testPolicy = Policy.Timeout(5, TimeoutStrategy.Pessimistic, (context, timespan, task) => { res = 1; Console.WriteLine("你已经超时了"); }); try { testPolicy.Execute(() => { Console.WriteLine("开始执行方法"); Thread.Sleep(10000); Console.WriteLine("执行结束了"); res = 2; }); } catch (Exception ex) { Console.WriteLine("异常了"); } Console.WriteLine("最后的结果是:" + res);
乐观超时(TimeoutStrategy.Optimistic),不会返回结果
var testPolicy = Policy.TimeoutAsync(5, TimeoutStrategy.Optimistic, (context, timespan, task) => { Console.WriteLine("你已经超时了"); }); try { var str = testPolicy.ExecuteAsync<string>((cancel) => { //如果5秒钟超时会触发 cancel.Register(() => { Console.WriteLine("你已经超时了 "); }); Console.WriteLine("开始执行方法"); Thread.Sleep(1000); Console.WriteLine("执行结束了"); return Task.FromResult(res.ToString()); }, CancellationToken.None); } catch (Exception ex) { Console.WriteLine("异常了"); }
重试
try { var policy = Policy.Handle<Exception>().Retry(5, (exception, count, context) => { Console.WriteLine($"第{count}次异常,异常信息:{exception.Message}"); }); Console.WriteLine("开始执行"); policy.Execute(() => { throw new Exception("我异常了"); }); } catch (Exception ex) { Console.WriteLine("进入最后的异常了"); }
重试等待
try { var policy = Policy.Handle<Exception>().WaitAndRetryAsync(5, (count) => { //每次等待时间一致 //return TimeSpan.FromSeconds(5); //根据次数等待时间不一样 return TimeSpan.FromSeconds(5 * count); }, (exception,timespan, count, context) => { Console.WriteLine($"第{count}次异常,等待时间:{timespan.TotalSeconds},异常信息:{exception.Message}"); }); Console.WriteLine("开始执行"); await policy.ExecuteAsync(() => { throw new Exception("我异常了"); }); } catch (Exception ex) { Console.WriteLine("进入最后的异常了"); }
熔断
try { //如果10秒内异常达到2次,则触发熔断,10秒之内不会访问方法体,只会返回熔断异常,10秒之后才会请求方法体 var policy = Policy.Handle<Exception>().CircuitBreakerAsync(2,TimeSpan.FromSeconds(10), (exception, timespan) => { Console.WriteLine($"开始等待:{timespan.TotalSeconds} s, 异常信息:{exception.Message}"); }, //如果等待10秒钟之后可以正常访问就会触发 () => { Console.WriteLine("熔断重置"); }, //每隔10秒钟触发 () => { Console.WriteLine("正在打开或者关闭熔断"); } ); Console.WriteLine("开始执行"); for (int i = 0; i < 20; i++) { Thread.Sleep(1000); try { await policy.ExecuteAsync(() => { throw new Exception("我异常了"); }); } catch (Exception ex) { Console.WriteLine(ex.Message); } } } catch (Exception ex) { Console.WriteLine("进入最后的异常了"); }
降级
try { //如果10秒内异常达到2次,则触发熔断,10秒之内不会访问方法体,只会返回熔断异常,10秒之后才会请求方法体 var policy = Policy<string>.Handle<Exception>().FallbackAsync((context,token) => { return Task.FromResult("降级异常"); }, (exception, context) => { return Task.FromResult("降级异常2"); }); Console.WriteLine("开始执行"); var res = await policy.ExecuteAsync(() => { throw new Exception("我异常了"); }); Console.WriteLine(res); } catch (Exception ex) { Console.WriteLine("不会进入这个异常"); }
请求限速
try { var rateLimit = Policy.RateLimit(2, TimeSpan.FromSeconds(1),6); for (int a = 0; a < 10; a++) { Thread.Sleep(500); for (int i = 0; i < 500; i++) { rateLimit.Execute(() => { Console.WriteLine("执行"); }); } } } catch (RateLimitRejectedException ex) { Console.WriteLine("策略异常" + ex.Message); }
在HttpClient拓展
引用NuGet包:
Install-Package Polly
Install-Package Microsoft.Extensions.Http.Polly
// 1、自定义异常处理(用缓存处理) var fallbackResponse = new HttpResponseMessage { Content = new StringContent("系统正繁忙,请稍后重试"),// 内容,自定义内容 StatusCode = HttpStatusCode.BadRequest // 定义返回的StatusCode }; services.AddHttpClient("mrico") // 1.1 降级(捕获异常,进行自定义处理) .AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().FallbackAsync(fallbackResponse, async b => { // 1、降级打印异常 Console.WriteLine($"开始降级,异常消息:{b.Exception.Message}"); // 2、降级后的数据 //Console.WriteLine($"降级内容响应:{}"); await Task.CompletedTask; })) // 1.2 熔断机制 .AddPolicyHandler(Policy<HttpResponseMessage>.Handle<Exception>().CircuitBreakerAsync(3, TimeSpan.FromSeconds(10), (ex, ts) => { Console.WriteLine($"断路器开启,异常消息:{ex.Exception.Message}"); Console.WriteLine($"断路器开启时间:{ts.TotalSeconds}s"); }, () => { Console.WriteLine($"断路器重置"); }, () => { Console.WriteLine($"断路器半开启(一会开,一会关)"); })) // 1.3 失败重试 .AddPolicyHandler(Policy<HttpResponseMessage> .Handle<Exception>() .WaitAndRetryAsync(50, (trycount) => { return TimeSpan.FromSeconds(2 * trycount); //每次等待的时间 })) //1.4、超时 .AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(2), TimeoutStrategy.Pessimistic, (context, timespan, task) => { return Task.FromResult(fallbackResponse); }));