簡介
Polly 是一個針對 .NET 應用程序的庫,提供了一系列經過優化的故障處理策略,幫助開發人員實現重試、斷路器、超時和熔斷機制等。通過 Polly 庫,開發人員可以更容易地編寫魯棒性更強、更可靠的應用程序。
Retry 策略
當出現異常或錯誤時,自動重試指定次數。
static void Main()
{
try
{
//捕獲DivideByZeroException異常會重試三次
var retryTwoTimesPolicy =
Policy
//處理多個異常類型通過OR即可
.Handle<DivideByZeroException>().Or<ArgumentException>()
.Retry(3, (ex, count) =>
{
Console.WriteLine("執行失敗! 重試次數 {0}", count);
Console.WriteLine("異常來自 {0}", ex.GetType().Name);
});
retryTwoTimesPolicy.Execute(() =>
{
var a = 0;
return 1 / a;
});
}
catch (Exception ex)
{
//第四次異常不做處理,拋出異常
Console.WriteLine($"catch {ex.GetType().Name}");
}
finally
{
Console.WriteLine($"finally");
}
}
static void Main()
{
try
{
//捕獲DivideByZeroException異常會重試三次
var retryTwoTimesPolicy =
Policy
//處理多個異常類型通過OR即可
.Handle<DivideByZeroException>().Or<ArgumentException>()
//添加重新間隔
.WaitAndRetry(new[]
{
TimeSpan.FromSeconds(1),
TimeSpan.FromSeconds(3),
TimeSpan.FromSeconds(5),
}, (ex, TimeSpan) =>
{
Console.WriteLine($"執行失敗! 執行間隔 {TimeSpan} {DateTime.Now}");
Console.WriteLine($"異常來自 {ex.GetType().Name}");
});
retryTwoTimesPolicy.Execute(() =>
{
var a = 0;
return 1 / a;
});
}
catch (Exception ex)
{
Console.WriteLine($"catch {ex.GetType().Name}");
}
finally
{
Console.WriteLine($"finally");
}
}
Timeout 策略
在規定時間內未獲取到響應時,自動取消請求並拋出超時異常。
static async Task Main()
{
// 創建超時策略,等待最多 1 秒鐘
// 如果在等待時間內未完成操作,則會拋出 TimeoutRejectedException 異常。
var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(1), TimeoutStrategy.Pessimistic);
try
{
// 在超時策略中執行操作
await timeoutPolicy.ExecuteAsync(async (ct) =>
{
using (HttpClient httpClient = new HttpClient())
{
var response = await httpClient.GetAsync("https://www.example.com", ct);
// 處理響應結果
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync(ct);
Console.WriteLine(content);
}
}, CancellationToken.None);
/*
* 最後,我們使用 ExecuteAsync 方法,在組合策略中執行異步操作,並在 CancellationToken 參數中傳遞 CancellationToken.None 來允許取消操作。
* 如果在指定的等待時間內沒有得到響應,則會拋出 TimeoutRejectedException 異常。如果操作失敗,則會捕獲異常並輸出相應的信息。
*/
}
catch (TimeoutRejectedException)
{
Console.WriteLine("The operation timed out.");
}
catch (Exception ex)
{
Console.WriteLine($"Exception caught: {ex.GetType().Name}");
}
}
Circuit Breaker 策略
當某個遠程服務發生異常或錯誤時,自動跳閘斷路,避免進一步請求對該服務造成負載壓力和損害。
static async Task Main()
{
//連續失敗 5 次,那麼斷路器會被打開,並保持 5 秒鐘的打開狀態時間,防止繼續執行相同的操作
var circuitBreakerPolicy = Policy
.Handle<Exception>()
.CircuitBreaker(5, TimeSpan.FromSeconds(5));
// 對多個操作使用相同的斷路器策略
for (int i = 0; i < 20; i++)
{
try
{
await Task.Delay(TimeSpan.FromSeconds(1));
// 嘗試執行某些可能會拋出異常的操作
circuitBreakerPolicy.Execute(() =>
{
// TODO: 執行某些操作,可能會拋出異常
throw new Exception($"異常");
});
}
catch (Exception ex)
{
// 斷路器開啓,操作被拒絕
Console.WriteLine($"time:{DateTime.Now} Num:{i} failed: {ex.Message}");
}
}
}
Microsoft.Extensions.Http.Polly
是基於 Polly 的一個 ASP.NET Core HttpClient 工廠的擴展庫,它能夠爲應用程序提供簡單易用的、可擴展的 HTTP 客戶端工廠,並且可以很容易地實現重試、熔斷、超時等策略。
var retryPolicy = HttpPolicyExtensions
.HandleTransientHttpError()
.Or<TimeoutRejectedException>() // thrown by Polly's TimeoutPolicy if the inner execution times out
.RetryAsync(3);
var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(10);
//更方便的使用polliy
services.AddHttpClient("example.com", c => c.BaseAddress = new Uri("http://example.com"))
.AddPolicyHandler(retryPolicy)
.AddPolicyHandler(timeoutPolicy);
參考
https://github.com/App-vNext/Polly
https://github.com/App-vNext/Polly.Extensions.Http/blob/master/README.md