作者:LamondLu
連結:https://www.cnblogs.com/lwqlun/p/8119856.html
什麼是Polly?
Polly是一款基於.NET的彈性及瞬間錯誤處理庫, 它允許開發人員以順暢及執行緒安全的方式執行重試(Retry),斷路器(Circuit),超時(Timeout),隔板隔離(Bulkhead Isolation)及後背策略(Fallback)。
Polly適用於.NET 4.0, .NET 4.5及.NET Standard 1.1(改寫.NET Core, Mono, Xamarin.IOS, Xamarin.Android, UWP, WP 8.1+)。
安裝Polly
.NET 4.0版本
Install-Package Polly.Net40Async
.NET 4.5及以上版本, .Net Standard 1.1
Install-Package Polly
彈性策略
Polly提供多種彈性策略。
重試策略
前提
程式會產生許多瞬時故障,但是在一定時間延遲之後,程式會自動糾正故障。
實現效果
允許配置自動重試。
斷路器策略
前提
當系統發生嚴重故障時,快速響應請求失敗比讓使用者等待要好。
避免故障系統過載有助於恢復系統。
實現效果
當系統錯誤超過預配置的數量,系統將斷路一段時間。
超時策略
前提
超出一定時間的等待,想要得到正確的結果是不太可能的。
實現效果
保證呼叫者不需要等待超時。
隔板隔離
前提
當行程出現故障,多個失敗的請求很容易佔滿伺服器資源(執行緒/CPU)。
一個處於故障狀態的下游系統,也會導致其上游系統故障。
實現效果
將嚴格管控故障行程,使其使用固定大小的資源池,隔離他們對其他行程的潛在影響
快取策略
前提
一定比例的請求可能是相似的。
實現效果
從快取中提供已知的響應。
當第一次讀取的時候,將響應自動快取起來。
後備策略
前提
當故障依然存在的時候,你打算做什麼。
實現效果
當程式依然發生故障時,執行指定操作。
包裝策略
前提
不同的故障需要不同的策略。包裝策略即組合策略。
實現效果
允許靈活的將以上任意幾種策略組合在一起。
如何使用Polly進行故障/異常處理?
Polly處理故障/異常有以下幾個步驟。
- 指定處理的異常/故障型別
- [可選] 指定處理的異常傳回值
- 指定處理策略
- 執行策略
指定處理異常/故障的型別
Polly使用Policy類的泛型方法Handle指定Polly需要處理異常/故障的型別。
指定單個異常型別
Policy.Handle<DivideByZeroException>()
指定帶條件的異常型別
Policy.Handle(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()
.OrInner(ex => ex.CancellationToken == myToken)
指定處理的異常傳回值
Polly除了支援處理異常/故障型別,還支援處理異常傳回值。所謂的處理異常結果,就是當Polly監控的方法,傳回某些特定結果時, Polly會觸發異常/故障處理策略。
Polly使用Policy類的泛型方法HandleResult制定Polly需要處理的異常結果.
指定觸發異常/故障處理策略的傳回值
例如:當某個方法的傳回值型別是HttpResposneMessage, 並且傳回值的StatusCode是NotFound時,觸發異常/故障處理策略。
Policy
.HandleResult(r => r.StatusCode == HttpStatusCode.NotFound)
指定多個傳回值
Policy
.HandleResult(r => r.StatusCode == HttpStatusCode.InternalServerError)
.OrResult(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()
.OrResult(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
指定異常處理策略
重試策略
重試一次
Policy
.Handle<DivideByZeroException>()
.Retry()
重試多次
Policy
.Handle<DivideByZeroException>()
.Retry(3)
重試多次,每次重試觸發一個行為
Policy
.Handle()
.Retry(3, (exception, retryCount) =>
{
// do something
});
永久重試(直到成功)
永久重試
Policy
.Handle<DivideByZeroException>()
.RetryForever()
永久重試,每次重試觸發一個行為
Policy
.Handle()
.RetryForever(exception =>
{
// do something
});
等待並重試
指定每個重試的間隔時間
Policy
.Handle()
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(2),
TimeSpan.FromSeconds(3)
});
在這個例子如果第一次出現異常,會在1秒後重試,如果依然出現異常,會在再次出現異常後2秒繼續重試,以此類推,下次異常後3秒繼續重試
每次重試,觸發一個行為
Policy
.Handle()
.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 onBreak = (exception, timespan) => { ... };
Action onReset = () => { ... };
CircuitBreakerPolicy breaker = Policy
.Handle()
.CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);
發生2次異常之後,斷開迴路1分鐘, 在觸發斷路時觸發onBreak方法,當重置斷路器時,觸發onReset方法
後備策略
Policy
.Handle<Whatever>()
.Fallback<UserAvatar>(UserAvatar.Blank)
當程式觸發異常/故障後,傳回一個備用值
Policy
.Handle()
.Fallback(() => UserAvatar.GetRandomAvatar())
當程式觸發異常/故障後,使用一個方法傳回一個備用值
Policy
.Handle()
.Fallback(UserAvatar.Blank, onFallback: (exception, context) =>
{
// do something
});
當程式觸發異常/故障後,傳回一個備用值,並觸發一個方法
Policy
.Handle()
.Fallback(UserAvatar.Blank, onFallback: (exception, context) =>
{
// do something
});
執行策略
Polly將監控DoSomething方法,如果發生DivideByZeroException異常,就使用重試策略
var policy = Policy
.Handle()
.Retry();
policy.Execute(() => DoSomething());
向Polly背景關係中傳遞任意值
var policy = Policy
.Handle()
.Retry(3, (exception, retryCount, context) =>
{
var methodThatRaisedException = context["methodName"];
Log(exception, methodThatRaisedException);
});
policy.Execute(
() => DoSomething(),
new Dictionary() {{ "methodName", "some method" }}
);
朋友會在“發現-看一看”看到你“在看”的內容