1. 程式人生 > >.NET的彈性及瞬間錯誤處理庫Polly

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

bulk 上下 安裝 see roi 服務器 rpo package available

原文:.NET的彈性及瞬間錯誤處理庫Polly

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

什麽是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處理故障/異常有以下幾個步驟。

  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" }}
);

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