一、背景
第一次接觸 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 "逾時";
}
}