一、背景
第一次接觸 Polly 還是在做某個微服務系統的時候,那時只會使用單一的超時策略與重試策略,更加高級的特性就沒有再進行學習了。最近開為某個客戶開發 PC 端的上位機的時候,客戶有個需求,在發起請求之后如果 5 秒鍾沒有響應則進行重試,總共可以重試 3 次,如果 3 次請求都未返回數據,就視為請求失敗。
關於 Polly 的高級用法可以參考官方的 Wiki 文檔即可,國內也有很多優秀的介紹文章,例如 這篇 和 這篇。
二、思路
查閱了 Polly 的官方文檔之后,發現 Polly 提供了策略組合功能,每個 Policy 實例都可以調用其 Wrap()
方法與另外一個策略進行組合。
或者是通過 Policy
靜態類提供的 Warp()
靜態方法來指定需要組合的兩個策略。
根據需求描述來看,我們需要用到超時策略和重試策略,只要將其組合即可。不過這里需要注意一個坑,即他們的組合順序。
正確的組合順序應該是 **重試策略.Warp(超時策略) **,而不是 超時策略.Warp(重試策略) 。這是因為在超時之后 Polly 會拋出 TimeoutRejectedException
異常,在重試策略捕獲到該異常之后,就會開始重試操作,即后面組合策略的 ExecuteAsync()
方法接收的委托。
三、實現
首先我們定義一個方法,該方法用於組合策略(超時+重試),因為我這里是傳入的異步委托操作,所以返回的是 AsyncPolicy
對象。
private AsyncPolicyWrap BuildTimeoutRetryPolicy(string msg)
{
// 超時策略,執行目標委托超過 5 秒則視為超時,拋出異常。
var timeoutPolicy = Policy.TimeoutAsync(5);
// 重試策略,重試 2 次,每次打印信息。
var retryPolicy = Policy.Handle<TimeoutRejectedException>().RetryAsync(2, (exception, i) =>
{
Console.WriteLine("開始第 i 次重試...");
});
return retryPolicy.WrapAsync(timeoutPolicy);
}
定義好策略之后,就是我們的實際應用了。這里說明一下執行邏輯,當第一次請求的時候如果發生了超時的情況,則進入重試策略,重試兩次,當最后一次仍然拋出 TimeoutRejectedException
異常,則重試策略不再捕獲,直接將異常拋出給調用者。
private async Task<string> GetResult(AsyncPolicyWrap policy)
{
try
{
return await policy.ExecuteAsync(() => SendDataAsync(sendProtocol));
}
catch (TimeoutRejectedException)
{
return "超時";
}
}