基於.NET的彈性及瞬間錯誤處理庫Polly

本文基本是官方說明的翻譯和總結(https://github.com/App-vNext/Pollygit

什麼是Polly?

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+)。緩存

安裝Polly

.NET 4.0版本安全

Install-Package Polly.Net40Async服務器

.NET 4.5及以上版本, .Net Standard 1.1dom

Install-Package Pollyide

彈性策略

Polly提供多種彈性策略。ui

重試策略

前提

程序會產生許多瞬時故障,可是在必定時間延遲以後,程序會自動糾正故障。spa

實現效果

容許配置自動重試。線程

斷路器策略

前提

當系統發生嚴重故障時,快速響應請求失敗比讓用戶等待要好。
避免故障系統過載有助於恢復系統。

實現效果

當系統錯誤超過預配置的數量,系統將斷路一段時間。

超時策略

前提

超出必定時間的等待,想要獲得正確的結果是不太可能的。

實現效果

保證調用者不須要等待超時。

隔板隔離

前提

當進程出現故障,多個失敗的請求很容易佔滿服務器資源(線程/CPU)。
一個處於故障狀態的下游系統,也會致使其上游系統故障。

實現效果

將嚴格管控故障進程,使其使用固定大小的資源池,隔離他們對其餘進程的潛在影響

緩存策略

前提

必定比例的請求多是類似的。

實現效果

從緩存中提供已知的響應。
當第一次讀取的時候,將響應自動緩存起來。

後備策略

前提

當故障依然存在的時候,你打算作什麼。

實現效果

當程序依然發生故障時,執行指定操做。

包裝策略

前提

不一樣的故障須要不一樣的策略。包裝策略即組合策略。

實現效果

容許靈活的將以上任意幾種策略組合在一塊兒。

如何使用Polly進行故障/異常處理?

Polly處理故障/異常有如下幾個步驟。

  1. 指定處理的異常/故障類型
  2. [可選] 指定處理的異常返回值
  3. 指定處理策略
  4. 執行策略

指定處理異常/故障的類型

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" }}
);
相關文章
相關標籤/搜索