.Net彈性和瞬態(tài)故障處理庫Polly介紹
Polly 是 .Net 下的一套瞬時故障處理及恢復(fù)的函式庫,可讓開發(fā)者以fluent及線程安全的方式來應(yīng)用諸如Retry、Circuit Breaker、Timeout、Bulkhead Isolation及Fallback等策略。
安裝
可以通過Nuget實現(xiàn)快速安裝:Install-Package Polly
基本用法
一個簡單的示例如下:
var policy = Policy .Handle<DivideByZeroException>() //定義所處理的故障 .Retry(); //故障的處理方法 policy.Execute(() => DoSomething()); //應(yīng)用策略
從上面的例子中我們可以看出,使用該策略一般包括三個步驟:
- 定義所處理的故障
- 定義故障的處理方法
- 應(yīng)用策略
上述代碼在功能上和下面的代碼等價:
for (int i = 0; i < 2; i++) { try { DoSomething(); } catch (DivideByZeroException) { if (i > 1) throw; } }
雖然這個例子比較簡單,帶來的優(yōu)越性并不明顯,但它以一種比較規(guī)范的方式定義了異常的處理策略,一來帶來了更好的體驗,帶來了更好的代碼可讀性,另外,隨著異常策略的復(fù)雜,它所帶來的對代碼的簡化就更加明顯了。下面就稍微詳細一點的深入介紹一下:
定義錯誤(故障)
常見故障定義方式是指定委托執(zhí)行過程中出現(xiàn)的特定異常,Polly中支持異常處理方式如下:
// 處理指定異常 Policy.Handle<DivideByZeroException>(); // 處理有條件的指定異常 Policy.Handle<SqlException>(ex => ex.Number == 1205); // 處理多種異常 Policy.Handle<DivideByZeroException>() .Or<ArgumentException>(); // 處理多種有條件的異常 Policy.Handle<SqlException>(ex => ex.Number == 1205) .Or<ArgumentException>(ex => ex.ParamName == "example");
也支持異常的聚合:
Policy.Handle<ArgumentException>() .Or<ArgumentException>();
另外,也支持通過返回值判斷是否故障:
// 指定錯誤的返回值 Policy.HandleResult<int>(ret => ret <= 0);
故障處理策略:重試
常見的處理策略是重試,Polly庫中內(nèi)置了各種常用的重試策略:
// 重試1次 Policy.Handle<TimeoutException>().Retry(); // 重試多次 Policy.Handle<TimeoutException>().Retry(3); // 無限重試 Policy.Handle<TimeoutException>().RetryForever();
也支持retry時增加一些額外的行為:
Policy.Handle<TimeoutException>().Retry(3, (err, countdown, context) => { // log retry });
也支持等待并重試:
// 等待并重試 Policy.Handle<TimeoutException>().WaitAndRetry(3, _ => TimeSpan.FromSeconds(3));
故障處理策略:回退(Fallback)
Fallback策略是在遇到故障是指定一個默認的返回值,
Policy<int>.Handle<TimeoutException>().Fallback(3); Policy<int>.Handle<TimeoutException>().Fallback(() => 3);
當(dāng)然,遇到?jīng)]有返回值的也可以指定故障時的處理方法,
Policy.Handle<TimeoutException>().Fallback(()?=>?{?});
使用Fallback時,異常被捕獲,返回默認的返回結(jié)果。
PS: 帶參數(shù)的Fallback處理方式貌似在5.0之后發(fā)生了變化,成了本文所示的方式,以前是Fallback<T>
故障處理策略:斷路保護(Circuit Breaker)
Circuit Breaker也是一種比較常見的處理策略,它可以指定一定時間內(nèi)最大的故障發(fā)生次數(shù),當(dāng)超過了該故障次數(shù)時,在該時間段內(nèi),不再執(zhí)行Policy內(nèi)的委托。下面以一個簡單的示例演示下該策略的功能:
static void testPolicy() { var circuitBreaker = Policy.Handle<TimeoutException>() .CircuitBreaker(3, TimeSpan.FromMinutes(1)); for (int i = 0; i < 5; i++) { try { circuitBreaker.Execute(DoSomething); } catch (Polly.CircuitBreaker.BrokenCircuitException e) { Console.WriteLine(e.Message); } catch (TimeoutException) { Console.WriteLine("timeout"); } } } static int index = 0; static int DoSomething() { Console.WriteLine($"DoSomething {index++}"); throw new TimeoutException(); }
執(zhí)行結(jié)果如下:
DoSomething 0 timeout DoSomething 1 timeout DoSomething 2 timeout The circuit is now open and is not allowing calls. The circuit is now open and is not allowing calls.
可以看到,前面3次都能執(zhí)行委托DoSomething,但出錯次數(shù)到達3次后,已經(jīng)進入斷路保護章臺,后面兩次調(diào)用直接返回BrokenCircuitException。直到達到保護時間超時后,對策略的調(diào)用才會再次執(zhí)行DoSomething委托。
這種策略在調(diào)用遠程服務(wù)時非常實用,當(dāng)一定時間內(nèi)的調(diào)用都出錯時,往往可以認為服務(wù)提供者已經(jīng)不可用,后續(xù)調(diào)用完全可以直接失敗,以避免重試的開銷。直到一定時間后才需要再次重試。
相對其它處理策略,CircuitBreaker是一個比較復(fù)雜的策略,它是有狀態(tài)的,可以通過CircuitState屬性獲?。?/p>
var state = circuitBreaker.CircuitState;
它有四種狀態(tài):
- CircuitState.Closed - 常態(tài),可執(zhí)行actions。
- CircuitState.Open - 自動控制器已斷開電路,不允許執(zhí)行actions。
- CircuitState.HalfOpen - 在自動斷路時間到時,從斷開的狀態(tài)復(fù)原。可執(zhí)行actions,后續(xù)的action/s或控制的完成,會讓狀態(tài)轉(zhuǎn)至Open或Closed。
- CircuitState.Isolated - 在電路開路的狀態(tài)時手動hold住,不允許執(zhí)行actions。
除了超時和策略執(zhí)行失敗的這種自動方式外,也可以手動控制它的狀態(tài):
// 手動打開(且保持)一個斷路器–例如手動隔離downstream的服務(wù) circuitBreaker.Isolate(); // 重置一個斷路器回closed的狀態(tài),可再次接受actions的執(zhí)行 circuitBreaker.Reset();
更多的介紹可以參看官方文檔:Circuit Breaker
故障封裝策略(PolicyWrap)
我們可以通過PolicyWrap的方式,封裝出一個更加強大的策略:
var fallback = Policy<int>.Handle<TimeoutException>().Fallback(100); var retry = Policy<int>.Handle<TimeoutException>().Retry(2); var retryAndFallback = fallback.Wrap(retry);
這個策略就是將Retry和Fallback組合起來,形成一個retry and fallback的策略,也可以寫成如下形式:
Policy.Wrap(fallback,?retry);
當(dāng)執(zhí)行這個新策略時:
retryAndFallback.Execute(DoSomething);
等價于執(zhí)行:
fallback.Execute(()=>?retry.Execute(DoSomething));
封裝策略本身是屬于彈性策略的范疇,這里只是提及一下,以演示Polly模塊強大的功能,關(guān)于彈性策略更多內(nèi)容在下文中再做更詳細的介紹。
到此這篇關(guān)于.Net彈性和瞬態(tài)故障處理庫Polly的文章就介紹到這了。希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
通過Web Service實現(xiàn)IP地址查詢功能的示例
下面小編就為大家分享一篇通過Web Service實現(xiàn)IP地址查詢功能的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12在ASP.NET Core5.0中訪問HttpContext的方法步驟
這篇文章主要介紹了在ASP.NET Core5.0中訪問HttpContext的方法步驟,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11.NET的DateTime函數(shù)獲取上個月的起始和截止時間的方法
這篇文章主要介紹了NET的DateTime函數(shù)獲取上個月的起始和截止時間的方法,可廣泛使用于報表中的時間自動選擇功能,是非常實用的技巧,需要的朋友可以參考下2015-01-01Asp.net的GridView控件實現(xiàn)單元格可編輯方便用戶使用
考慮到用戶使用方便,減少彈出頁面,采用點“編輯”按鈕無需彈出頁面直接當(dāng)前行的單元格內(nèi)容就能編輯,思路及代碼如下,有此需求的朋友可以參考下,希望對大家有所幫助2013-08-08asp.net中EXCEL數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫的方法
這篇文章主要介紹了asp.net中EXCEL數(shù)據(jù)導(dǎo)入到數(shù)據(jù)庫的方法,實現(xiàn)讀取excel數(shù)據(jù)并導(dǎo)入到SQL Server數(shù)據(jù)庫的功能,是非常實用的技巧,需要的朋友可以參考下2015-01-01Asp.net FileUpload+Image制作頭像效果示例代碼
個人信息中通常需要自己的頭像或者照片,今天主要介紹一下使用FileUpload+img控件上傳照片,感興趣的朋友可以參考下2013-08-08