HttpClientFactory系列二:集成Polly处理瞬态故障
前言:最近,同事在工作中遇到了使用HttpClient,有些請求超時的問題,輔導(dǎo)員讓我下去調(diào)研一下,HttpClinet的使用方式已經(jīng)改成了之前博客中提到的方式,問題的原因我已經(jīng)找到了,就是因為使用了偽異步,導(dǎo)致阻塞主線程。在之前的博客中有園友,建議在使用靜態(tài)的HttpClinet時務(wù)必使用它的Async方法,所以就得從頭到尾異步化。這一點在之前的文章中沒有提,這里作為補充,也感謝這位園友。關(guān)于怎么使用異步編程,在這里我就不聊了,大家可以看看其他的博客,看完公司的代碼之后,我想強調(diào)的是,在使用異步編程的時候,關(guān)于返回值的問題:
為什么async方法返回的通常都是Task或者Task<T>,而不是T本身?這是因為,Task和Task<T>代表著在將來某一個時刻將會返回T類型的結(jié)果。因此,在主線程調(diào)用HttpPostWhitStrBody時,實際上你拿到的是一個未來才會發(fā)生的預(yù)期,也就是未來的某一個時間會得到一個string的結(jié)果。如果返回的是一個T本身,那么,在主線程調(diào)用時就會因為訪問這個需要一段時間才能給出結(jié)果,從而阻塞了主線程。因此,如果async方法有返回值,應(yīng)返回Task<T>。如果沒有返回值,應(yīng)該返回Task。大家如果不太明白的話,建議多了解一下C#中的異步編程。好了,前戲太多了,下面就來聊聊如何集成Polly。?
一、在異步編程中如何處理異常信息
在聊如何集成Polly前,我們先來看看在異步編程中如何處理異常。當(dāng)異步操作發(fā)生異常的時候,異常會停留在異步方法中,調(diào)用方法無法直接看到,因此,我們應(yīng)該異步方法中處理異常,而不是在調(diào)用方法中處理異常。如果我們使用了await修飾了任務(wù),那么,只需要為它包上一層try-catch就可以了。當(dāng)然了,也可以在調(diào)用方法(比如Main方法中)捕捉異常,這就需要異常從異步方法中傳播給調(diào)用方法。做到這件事是很容易的,只需要兩個條件:
(1)調(diào)用方法本身也是async的,并且,在內(nèi)部調(diào)用異步方法,并使用await。
(2)異步方法返回Task或者Task<T>
因為C#不允許在Main方法中使用async(在C#7.1中,可以使用async修飾Main方法了),因此,我們不得不再創(chuàng)建一層方法,下面通過代碼演示一下。
一般在處理異常的時候,我們都是采用?try-catch來做處理的,若我們想重試三次,此時我們只能進(jìn)行循環(huán)三次操作。我們只能簡單進(jìn)行處理,自從有了Polly,什么重試機制,超時都不在話下,下面把話題轉(zhuǎn)向Polly。
在聊下面的話題時,建議大家先認(rèn)真閱讀一下這篇博客,因為博主講的非常細(xì)致:Polly
?
二、集成Polly,處理HTTP請求過程中的瞬時故障
? Polly是一種流行的瞬態(tài)故障處理庫,它提供了一種機制來定義可在某些故障發(fā)生時應(yīng)用的策略。 最常用的策略之一就是重試策略。 這中策略允許您包裝一些代碼,如果發(fā)生故障,將重試這些代碼; 必要時也可以重試多次。 這在您的應(yīng)用程序需要與外部服務(wù)通信的情況下非常有用。 當(dāng)通過HTTP與服務(wù)進(jìn)行通信時,會出現(xiàn)瞬態(tài)故障,這種風(fēng)險始終存在。 瞬態(tài)故障可能會阻礙您的請求完成,但是瞬態(tài)故障也可能是暫時性的問題。因此, 這使得在這些情況下重試成為明智的選擇。
? 除了重試之外,Polly還提供了許多其他類型的策略,其中許多策略可能需要與重試相結(jié)合,以構(gòu)建處理故障的復(fù)雜方法。 我將在本文中介紹一些更一般的例子,但是如果你想要更全面的了解,我建議你查看一下Polly wiki。
使用Polly
ASP.NET團(tuán)隊與Polly的主要維護(hù)者Dylan和Joel密切合作,使得將Polly策略應(yīng)用于HttpClient實例非常簡單。在開始之前我們先引用下面的兩個包:
? 這個Microsoft.Extensions.Http.Polly包在IHttpClientBuilder上包含一個名為AddPolicyHandler的擴展方法,我們可以使用它來添加一個handler?,該handler?將使用一個Polly實例,來包裝請求。?
我們可以用這個擴展在我們的ConfigureServices 方法中,代碼如下:
services.AddHttpClient("github").AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(TimeSpan.FromSeconds(10)));
? 在這個例子中,我們定義了一個名字為“github”的客戶端,并且我們使用AddPolicyHandler 方法來添加了一種處理超時的策略,這里提供的超時策略,必須是IAsyncPolicy<HttpResponseMessage>,這個中策略在任何請求超過10s都會觸發(fā)。
?重試策略
如果可能的話,當(dāng)我們在使用Polly時,最好的嘗試是,定義一次策略并在應(yīng)用相同策略的情況下共享它們,這樣要更改策略,只需在一個位置進(jìn)行更改。此外,它還確保僅分配策略一次。當(dāng)然了,如果多個使用者希望通過相同的斷路器實例運行,則需要共享諸如斷路器之類的策略。不太理解,不要緊,下面看代碼,體會一下。
瞬時錯誤處理
處理HTTP請求時,我們要處理的最常的問題就是瞬態(tài)故障。 由于這是一個常見的要求,Microsoft.Extensions.Http.Polly軟件包中包含一個特定的擴展,我們可以使用它來快速設(shè)置處理瞬時故障的策略。
例如,要在指定客戶端的請求發(fā)生瞬時故障時添加基本重試,我們可以按如下方式注冊重試策略:
services.AddHttpClient("github").AddTransientHttpErrorPolicy(p => p.RetryAsync(3));?
代碼的含義是,所以使用命名的HttpClient,發(fā)出的請求,只要遇到錯誤,就會重試三次。這個AddTransientHttpErrorPolicy?方法需要一個Func<PolicyBuilder<HttpResponseMessage>, IAsyncPolicy<HttpResponseMessage>>.類型的參數(shù)。此處的PolicyBuilder將預(yù)先配置為處理HttpRequestExceptions,任何返回5xx狀態(tài)代碼的響應(yīng)以及具有408(請求超時)狀態(tài)代碼的任何響應(yīng)。 這應(yīng)該適用于許多情況。 如果您要求在其他條件下應(yīng)用策略,則需要使用不同的重載來傳遞更具體的策略。
我們需要意識到, 在進(jìn)行重試時,我們需要考慮冪等性。 重試HTTP GET是一種非常安全的操作。因為HTTP GET本身就是冪等性的, 如果我們調(diào)用一個方法但沒有收到任何響應(yīng),我們可以安全地重試調(diào)用而不會有任何危險。 但是,請考慮如果我們重試HTTP POST請求會發(fā)生什么? 在這種情況下,我們必須更加小心,因為您的原始請求可能實際收到,但我們收到的響應(yīng)卻顯示失敗。 在這種情況下,重試可能導(dǎo)致數(shù)據(jù)重復(fù)或下游系統(tǒng)中存儲的數(shù)據(jù)損壞。 在這里,您需要更多地了解下游服務(wù)在多次收到相同請求時將執(zhí)行的操作。 重試是一種安全操作? 當(dāng)您擁有下游服務(wù)時,更容易控制它。 例如,您可以使用一些唯一標(biāo)識符來防止重復(fù)的POST。
如果您對下游系統(tǒng)的控制較少,或者您知道重復(fù)的POST可能會產(chǎn)生負(fù)面影響,則需要更仔細(xì)地控制策略。 可能適合的做法是定義不同的命名/類型客戶端。 您可以為那些沒有副作用的請求創(chuàng)建一個,而為那些有副作用的請求創(chuàng)建另一個。 然后,您可以使用正確的客戶端進(jìn)行操作。 但是,這可能會變得有點難以管理。 更好的選擇是使用AddPolicyHandler的重載,它允許我們訪問HttpRequestMessage,以便可以有條件地應(yīng)用策略。 那個重載看起來像這樣:AddPolicyHandler(Func<HttpRequestMessage, IAsyncPolicy<HttpResponseMessage>> policySelector),您將注意到此處的policySelector委托可以訪問HttpRequestMessage,并且應(yīng)該返回IAsyncPolicy <HttpResponseMessage>。 我們無法訪問PolicyBuilder設(shè)置來處理瞬態(tài)錯誤,就像我們在前面的示例中所做的那樣。 如果我們想要處理常見的瞬態(tài)錯誤,我們需要為我們的策略定義預(yù)期條件。 為了簡化這一過程,Polly項目包含一個幫助擴展,我們可以使用它來設(shè)置一個準(zhǔn)備好處理常見瞬態(tài)錯誤的PolicyBuilder。 要使用擴展方法,我們需要從Nuget添加Polly.Extensions.Http包。
然后,我們可以調(diào)用HttpPolicyExtensions.HandleTranisentHttpError()來獲取配置瞬態(tài)故障條件的PolicyBuilder。 我們可以使用該PolicyBuilder創(chuàng)建一個合適的重試策略,當(dāng)請求是HTTP GET時,可以有條件地應(yīng)用該策略。 在此示例中,任何其他HTTP方法都使用NoOp策略。
使用PolicyRegistry
我想在本文中介紹的最后一個示例是如何從策略注冊表中應(yīng)用策略。 為了支持策略重用,Polly提供了PolicyRegistry的概念,PolicyRegistry本質(zhì)上是策略的容器。 這些可以在應(yīng)用程序啟動時通過向注冊表添加策略來定義。 然后可以傳遞注冊表并用于按名稱訪問策略。IHttpClientBuilder上可用的擴展還支持使用注冊表將基于Polly的處理程序添加到客戶端。
首先,我們必須在DI中注冊PolicyRegistry。 Microsoft.Extensions.Http.Polly包中包含一些擴展方法,以簡化此操作。 在上面的示例中,我調(diào)用AddPolicyRegistry方法,該方法是IServiceCollection的擴展。 這將創(chuàng)建一個新的PolicyRegistry,并在DI中添加注冊,作為IPolicyRegistry <string>和IReadOnlyPolicyRegistry <string>的實現(xiàn)。 該方法返回策略,以便我們有權(quán)向其添加策略。
?在此示例中,我們添加了兩個超時策略并為其指定了名稱。 現(xiàn)在,在注冊客戶端時,我們可以調(diào)用IHttpClientBuilder上的AddPolicyHandlerFromRegistry方法。 這將采用我們想要使用的策略的名稱。 當(dāng)工廠創(chuàng)建此命名客戶端的實例時,它將添加適當(dāng)?shù)奶幚沓绦?#xff0c;在“regular”重試策略中包含調(diào)用,該策略將從注冊表中檢索。?
示例項目:新建一個.Net Core 2.1的webapi項目:
Startup.cs文件的代碼:
注意:
WaitAndRetryAsync參數(shù)的意思是:每次重試時等待的睡眠持續(xù)時間。ValuesController的代碼:
看到?jīng)],它在重試。
? 更多的Polly和HttpClinetFactory的集成使用請參考:
https://github.com/App-vNext/Polly/wiki/Polly-and-HttpClientFactory
https://www.hanselman.com/blog/AddingResilienceAndTransientFaultHandlingToYourNETCoreHttpClientWithPolly.aspx?
三、總結(jié)
注意:AddTransientHttpErrorPolicy方法會自動幫我們處理以下錯誤:
(1)Network failures (System.Net.Http.HttpRequestException)
(2)HTTP 5XX status codes (server errors)
(3)HTTP 408 status code (request timeout)?
通過這些庫,您可以輕松地啟動并運行能夠無縫處理瞬態(tài)故障的HttpClient實例。?有關(guān)更詳細(xì)的Polly文檔和示例,建議您查看Polly wiki。這里只是聊了關(guān)于HttpClientFactory中集成Polly的基礎(chǔ)用法,關(guān)于更詳細(xì)的使用請參考:https://www.cnblogs.com/CreateMyself/p/7589397.html,好了今天就聊到這里,該系列文章還有最后一篇,對于Polly我也是剛接觸,至于項目中是否使用還要經(jīng)過輔導(dǎo)員的審核,希望對你有幫助,謝謝。?
?參考文章:
(翻譯)https://www.stevejgordon.co.uk/httpclientfactory-using-polly-for-transient-fault-handling
相關(guān)文章:
ASP.Net Core2.1中的HttpClientFactory系列一:HttpClient的缺陷
.NET Core 中正確使用 HttpClient 的姿勢
AspNetCore 基于AOP實現(xiàn)Polly的使用
使用.NetCore 控制臺演示 熔斷 降級(polly)
.NET Core微服務(wù)之基于Polly+AspectCore實現(xiàn)熔斷與降級機制
再探Circuit Breaker之使用Polly
開源服務(wù)容錯處理庫Polly使用文檔
Polly組件對微服務(wù)場景的價值
原文地址:https://www.cnblogs.com/runningsmallguo/p/9692001.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的HttpClientFactory系列二:集成Polly处理瞬态故障的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Ocelot简易教程(四)之请求聚合以及
- 下一篇: 《Office 365开发入门指南》上市