Polly
.NET foundation 的 Polly 專案是為了解決暫時性錯誤處理(transient-fault-handling)的一個函式庫,裡面提供了處理眾多相關錯誤處理的函式呼叫。
目前的應用程式越來越少是自己獨立作業就把一個 request 或是一項作業給處理完成的,通常都會跟內部或是外部系統合作,而這個部份通常為了解相依關係,會定義好介面常見的就是定義 Api 他的傳入與回傳值,尤其是在這個微服務觀念盛行的時期,這個作法尤其常見。
但是像這種鬆耦合的系統架構,雖然美其名是開發/佈署不會互相影響彼此,但單一服務獨活於系統中又顯的很雞肋,偏偏依賴 Api 的方式其實並不可靠,網路基本上就不是建立在可靠的傳輸之上,所以連線失敗/服務暫時下線可以說是需要假定會隨時發生的事情。
不過很多時候這種連線失敗很可能只是一個突波,下一個 request 可能就成功了,而 Polly 就像是把這些繁瑣設定與工作包起來方便重複使用的函式庫。
其實這個函式庫,跟混亂工程有著密不可分的關係,不過這個部份主題很大,這篇就不提了,只列出一些可以供參考的資料。
Demo source code
GitHub: link
How to install Polly
若你覺得安裝 Package 就是一行 nuget 指令就可以,那其實也沒錯,不過你會發現 Polly 這個套件相依的 packages 預設實在多的驚人。
Install-Package Polly -Version 7.1.1
真的這樣幹的話你會發現,用預設的版本安裝相依套件的話,它會幫你安裝超多 System 相關的 Library, 主要原因就是 NETStandard.Library
預設安裝的版本實在太低,導致這些東西會一起裝進去,若想要避免這種情況,的話就需要先把相依的套件先升級。
- Install Microsoft.NETCore.Platforms
這是為了 NETStandard 2.x
要安裝的 預設版本號是需要大於 1.1.0
不過這邊可以先升到頂
- Install NETStandard.Library
這邊就直接裝到 2.x 以上的版本,Polly 目前的版本 (7.1.1
) 預設最低版號要求到 1.6.1
,但若真的只裝到 1.6.1
的話就需要安裝一堆 System 相關的套件,所以不太推薦。
- Install Polly
這個時候安裝 Polly 就會發現它不會發瘋似的要求你安裝一堆看起來系統本身就有的東西。乾淨又清爽。
Polly Resilience policies
Polly 提供很多錯誤處理的方法,這些可以解決大多數發生的暫時性錯誤問題,而且這些方法還可以用 PolicyWrap 給包裝成一組錯誤處理方法。以下僅列出部份 Polly 這個 Library 內建好的一些錯誤處理機制和應用情境。
Policy | 適用情境 |
---|---|
Retry | 概念:錯誤只是暫時的,它會自己修復好。像是網路連線問題,發生突波讓連線暫時很難連上。 |
Circuit-breaker | 概念:暫時停止送出 request 給一個已經發生錯誤的系統/服務。若藉由暫緩 request 的進入可以讓服務自行恢復那就暫止 request 進入該服務一段時間。 |
Timeout | 概念:request 超過一定的時間就會返回 timeout 錯誤訊息。 |
Cache | 概念:通常回應的東西在一定時間內不會改變,或是通常改變的機率不大,且資訊的即時性沒有相當的要求。 |
Resilience policies - Retry
Retry 這邊基本的用法簡單易懂,就是發生指定的錯誤就讓它馬上再打指定次數。
|
|
而 retry 還有另一種等待指定時間後再 try 一次
|
|
上述只是設定 Policy ,要讓這些 Policy 發揮作用的話需要讓執行方法在這個 Policy 中呼叫
|
|
Resilience policies - Circuit-breaker
斷路器的運作基本上不脫離以下這個狀態機
有 Open / Closed / Half Open 這三個,而 Api 的呼叫還多了一個 Isolated 這個狀態。不過主要還是針對那三個狀態做不同的處理。
一般的情況下斷路器的狀態若是 Closed 代表系統正常運作中,程式會執行原本要去執行的區段。若是發生指定捕捉的 Exception 的話且有達到設定的上限時就會讓狀態變成 Open。在 Open 狀態下斷路器就會執行 OnBreak(若有設定 OnBreak function 的話)的程式區段,而預設的情況下是會直接把該 Exception 直接拋出。
斷路器的基本用法就是停止呼叫該方法(API或操作)一段時間,在指定時間內都直接返回 Exception。時間過後再次嘗試呼叫該方法。
|
|
除了上述的基本用法其實這個方法還有更進階的選項,讓使用上可以控制更多細節
|
|
因為斷路器需要記憶當前的狀態,所以 CircuitBreakerPolicy 這個實體必須要獲得到同一個,若使用 IoC 容器並讓 Policy 每次取得的都是新的話,就會讓這個斷路器的運作不如預期。詳情可以參考一下這篇文章。
Resilience policies - Cache
這個 Policy 其實就是 Cache,恩…這是廢話,也是這個 Policy 的全部。不過這個 Cache 他有分成 in-memory 和 distribute cache (eg. Redis, Distributed MSSQL Server Cache)這兩個不同的套件。
它可以設定 Cache 的 TTL (恩…很基本),不過它還可以設定 Cache 在存放時 / 取得時 / 沒打到時 / 發生各種錯誤時 的對應方法,這點倒是滿不錯的,讓你在處理 Cache 時有更多控制權。
Resilience policies - PolicyWrap
個人覺得 Polly 會好用很大部份歸功於它可以讓眾多 Policy 可以組合在一起使用,這也比較符合一般的使用情境。一個簡單的執行範例像是以下例子。
|
|
本來一個作業發生的 Exception 就不太可能只有一種,而發生不同的 Exception 需要不同的處理方式也是挺合理的。所以 Warp 方法將這些 Policy 組合在一起就讓這個套件變成了相當好用的神兵利器。
Reference
Polly
- Official Site
- Github Polly
- Implement HTTP call retries with exponential backoff with HttpClientFactory and Polly policies
- Retry Patterns
- Polly and HttpClientFactory
- Circuit Breaker pattern
- Implement the Circuit Breaker pattern
Chaos Engineering
- PRINCIPLES OF CHAOS ENGINEERING
- Chaos Engineering: the history, principles, and practice
- InfoQ CN- Chaos Engineering: the history, principles, and practice
- AWS Official CN Blog- Choas Engineering
- Chaos Engineering is Not Just Tools—It’s Culture
- Chaos engineering resources
Chaos Engineering Tool