本文基本是官方說明的翻譯和總結(https://github.com/App-vNext/Polly)git
Polly是一款基於.NET的彈性及瞬間錯誤處理庫, 它容許開發人員以順暢及線程安全的方式執行重試(Retry),斷路器(Circuit),超時(Timeout),隔板隔離(Bulkhead Isolation)及後背策略(Fallback)。github
Polly適用於.NET 4.0, .NET 4.5及.NET Standard 1.1(覆蓋.NET Core, Mono, Xamarin.IOS, Xamarin.Android, UWP, WP 8.1+)。緩存
.NET 4.0版本安全
Install-Package Polly.Net40Async
服務器
.NET 4.5及以上版本, .Net Standard 1.1dom
Install-Package Polly
ide
Polly提供多種彈性策略。ui
程序會產生許多瞬時故障,可是在必定時間延遲以後,程序會自動糾正故障。spa
容許配置自動重試。線程
當系統發生嚴重故障時,快速響應請求失敗比讓用戶等待要好。
避免故障系統過載有助於恢復系統。
當系統錯誤超過預配置的數量,系統將斷路一段時間。
超出必定時間的等待,想要獲得正確的結果是不太可能的。
保證調用者不須要等待超時。
當進程出現故障,多個失敗的請求很容易佔滿服務器資源(線程/CPU)。
一個處於故障狀態的下游系統,也會致使其上游系統故障。
將嚴格管控故障進程,使其使用固定大小的資源池,隔離他們對其餘進程的潛在影響
必定比例的請求多是類似的。
從緩存中提供已知的響應。
當第一次讀取的時候,將響應自動緩存起來。
當故障依然存在的時候,你打算作什麼。
當程序依然發生故障時,執行指定操做。
不一樣的故障須要不一樣的策略。包裝策略即組合策略。
容許靈活的將以上任意幾種策略組合在一塊兒。
Polly處理故障/異常有如下幾個步驟。
Polly使用Policy類的泛型方法Handle指定Polly須要處理異常/故障的類型。
指定單個異常類型
Policy.Handle<DivideByZeroException>()
指定帶條件的異常類型
Policy.Handle<SqlException>(ex => ex.Number == 1205)
Polly也支持指定多種異常/故障類型, 這裏須要使用Or方法
Policy.Handle<DivideByZeroException>().Or<ArgumentException>()
指定多個帶條件的異常類型
Policy .Handle<SqlException>(ex =ex.Number == 1205) .Or<ArgumentException>(ex =ex.ParamName == "example")
Polly也支持指定內部異常
Policy .HandleInner<HttpResponseException>() .OrInner<OperationCanceledException>(ex => ex.CancellationToken == myToken)
Polly除了支持處理異常/故障類型,還支持處理異常返回值。所謂的處理異常結果,就是當Polly監控的方法,返回某些特定結果時, Polly會觸發異常/故障處理策略。
Polly使用Policy類的泛型方法HandleResult制定Polly須要處理的異常結果.
指定觸發異常/故障處理策略的返回值
例如:當某個方法的返回值類型是HttpResposneMessage, 而且返回值的StatusCode是NotFound時,觸發異常/故障處理策略。
Policy .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.NotFound)
指定多個返回值
Policy .HandleResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.InternalServerError) .OrResult<HttpResponseMessage>(r => r.StatusCode == HttpStatusCode.BadGateway)
同時指定異常類型和返回值
HttpStatusCode[] httpStatusCodesWorthRetrying = { HttpStatusCode.RequestTimeout, // 408 HttpStatusCode.InternalServerError, // 500 HttpStatusCode.BadGateway, // 502 HttpStatusCode.ServiceUnavailable, // 503 HttpStatusCode.GatewayTimeout // 504 }; HttpResponseMessage result = Policy .Handle<HttpResponseException>() .OrResult<HttpResponseMessage>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
重試一次
Policy .Handle<DivideByZeroException>() .Retry()
重試屢次
Policy .Handle<DivideByZeroException>() .Retry(3)
重試屢次,每次重試觸發一個行爲
Policy .Handle<DivideByZeroException>() .Retry(3, (exception, retryCount) => { // do something });
永久重試
Policy .Handle<DivideByZeroException>() .RetryForever()
永久重試,每次重試觸發一個行爲
Policy .Handle<DivideByZeroException>() .RetryForever(exception => { // do something });
指定每一個重試的間隔時間
Policy .Handle<DivideByZeroException>() .WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) });
在這個例子若是第一次出現異常,會在1秒後重試,若是依然出現異常,會在再次出現異常後2秒繼續重試,以此類推,下次異常後3秒繼續重試
每次重試,觸發一個行爲
Policy .Handle<DivideByZeroException>() .WaitAndRetry(new[] { TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3) }, (exception, timeSpan) => { // do something });
在發生指定次數的異常/故障以後,斷開回路
Policy .Handle<DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1));
發生2次異常以後,斷開回路1分鐘
Action<Exception, TimeSpan> onBreak = (exception, timespan) => { ... }; Action onReset = () => { ... }; CircuitBreakerPolicy breaker = Policy .Handle<DivideByZeroException>() .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);
發生2次異常以後,斷開回路1分鐘, 在觸發斷路時觸發onBreak方法,當重置斷路器時,觸發onReset方法
後備策略
Policy .Handle<Whatever>() .Fallback<UserAvatar>(UserAvatar.Blank)
當程序觸發異常/故障後,返回一個備用值
Policy .Handle<Whatever>() .Fallback<UserAvatar>(() => UserAvatar.GetRandomAvatar())
當程序觸發異常/故障後,使用一個方法返回一個備用值
Policy .Handle<Whatever>() .Fallback<UserAvatar>(UserAvatar.Blank, onFallback: (exception, context) => { // do something });
當程序觸發異常/故障後,返回一個備用值,並觸發一個方法
Policy .Handle<Whatever>() .Fallback<UserAvatar>(UserAvatar.Blank, onFallback: (exception, context) => { // do something });
Polly將監控DoSomething方法,若是發生DivideByZeroException異常,就使用重試策略
var policy = Policy .Handle<DivideByZeroException>() .Retry(); policy.Execute(() => DoSomething());
向Polly上下文中傳遞任意值
var policy = Policy .Handle<DivideByZeroException>() .Retry(3, (exception, retryCount, context) => { var methodThatRaisedException = context["methodName"]; Log(exception, methodThatRaisedException); }); policy.Execute( () => DoSomething(), new Dictionary<string, object>() {{ "methodName", "some method" }} );