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); }));