天天看點

使用 Polly 實作複雜政策(逾時重試)

一、背景

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