前言
簡單整理一下polly 重試。
正文
在開發程式中一般都有一個重試幫助類,那麼polly同樣有這個功能。
polly 元件包:
polly 功能包
polly.Extensions.Http 專門針對http的擴充包
Miscrosoft.Extension.Http.Polly 看到這個名字,那麼99%是針對官方.net core的擴充包,是HttpClientFactory 的擴充。
polly有下面一些功能:
- 失敗重試
- 服務熔斷
- 逾時處理
- 艙壁處理
- 緩存政策
- 失敗降級
- 組合政策
其他都好了解,但是艙壁處理 是什麼呢?
這個是限流功能,服務定義最大的流量和隊列,避免請求量過大而崩潰。
組合政策,就是對上面的功能可以***組合。
polly 使用步驟:
- 定于要處理的異常類型和傳回值
- 定義要處理的工作
- 使用定義的政策來執行代碼
polly的源代碼:
https://github.com/App-vNext/Polly
polly 針對http的擴充包:
https://github.com/App-vNext/Polly.Extensions.Http
适合polly 重試的場景:
1.服務"失敗"是短暫的,可自愈的。
針對這種http請求,無狀态的是非常适用的。
2.服務是"幂等"的,重複調用不會産生副作用
這個幂等可以簡單為多次執行,并不會影響到最初達到的效果。
比如說個人查詢,查詢多次的話,效果是相同的。具體幂等可以百度一下,不過覺的看下https://baike.baidu.com/item/%E5%B9%82%E7%AD%89/8600688?fr=aladdin就夠了,因為有些人講的神乎其神。
具體場景:
- 服務閃斷
- 部分節點不可用
在使用重試過程中,最好達到下面幾個要求:
- 設定失敗次數
- 設定有步長政策的失敗等待間隔
- 設定降級響應
- 設定斷路器
前面說過polly 是針對httpClientFactory 的擴充,那麼其融合性其實是非常好的。
比如說,grpc當監聽到AddTransientHttpErrorPolicy錯誤的時候,那麼可以啟動對應的政策進行重試,RetryAsync就是polly的擴充,裡面設定重試次數20次。
services.AddGrpcClient<Helloworld.Greeter.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
}).ConfigurePrimaryHttpMessageHandler(provider =>
{
var handle = new SocketsHttpHandler();
handle.SslOptions.RemoteCertificateValidationCallback = (a, b, c, d) => true;
return handle;
}).AddTransientHttpErrorPolicy(p=>p.RetryAsync(20));
看下AddTransientHttpErrorPolicy,其實個人感覺RetryAsync倒是沒有必要去看,看AddTransientHttpErrorPolicy 是為了知道啥時候會觸發這個重試,以及知道如何去定義我們自己的Policy。
AddTransientHttpErrorPolicy:
public static IHttpClientBuilder AddTransientHttpErrorPolicy(
this IHttpClientBuilder builder,
Func<PolicyBuilder<HttpResponseMessage>, IAsyncPolicy<HttpResponseMessage>> configurePolicy)
{
if (builder == null)
{
throw new ArgumentNullException(nameof(builder));
}
if (configurePolicy == null)
{
throw new ArgumentNullException(nameof(configurePolicy));
}
var policyBuilder = HttpPolicyExtensions.HandleTransientHttpError();
// Important - cache policy instances so that they are singletons per handler.
var policy = configurePolicy(policyBuilder);
builder.AddHttpMessageHandler(() => new PolicyHttpMessageHandler(policy));
return builder;
}
從名字中可以看到HandleTransientHttpError就是處理異常的。
public static PolicyBuilder<HttpResponseMessage> HandleTransientHttpError()
{
return Policy<HttpResponseMessage>.Handle<HttpRequestException>().OrTransientHttpStatusCode();
}
這裡表示HttpRequestException 會觸發,或者OrTransientHttpStatusCode一些狀态碼下會觸發,看下OrTransientHttpStatusCode。
OrTransientHttpStatusCode:
public static PolicyBuilder<HttpResponseMessage> OrTransientHttpStatusCode(
this PolicyBuilder<HttpResponseMessage> policyBuilder)
{
if (policyBuilder == null)
throw new ArgumentNullException(nameof (policyBuilder));
return policyBuilder.OrResult(HttpPolicyExtensions.TransientHttpStatusCodePredicate);
}
檢視HttpPolicyExtensions.TransientHttpStatusCodePredicate:
private static readonly Func<HttpResponseMessage, bool> TransientHttpStatusCodePredicate = (Func<HttpResponseMessage, bool>) (response => response.StatusCode >= HttpStatusCode.InternalServerError || response.StatusCode == HttpStatusCode.RequestTimeout);
這裡面表示 HttpStatusCode.InternalServerError(500)和 HttpStatusCode.RequestTimeout(408) 會進行重試。
同樣可以設定間隔時間進行重試:
services.AddGrpcClient<Helloworld.Greeter.GreeterClient>(options =>
{
options.Address = new Uri("https://localhost:5001");
}).ConfigurePrimaryHttpMessageHandler(provider =>
{
var handle = new SocketsHttpHandler();
handle.SslOptions.RemoteCertificateValidationCallback = (a, b, c, d) => true;
return handle;
}).AddTransientHttpErrorPolicy(p=>p.WaitAndRetryAsync(20,i=>TimeSpan.FromSeconds(2)));
還可以使用WaitAndRetryForever 表示一直重試,直到成功,看需求。
同樣也可以自定義一些狀态或者一些情況,做一些事情:
var reg = services.AddPolicyRegistry();
reg.Add("retryforever", Policy.HandleResult<HttpResponseMessage>(message =>
{
return message.StatusCode == System.Net.HttpStatusCode.Created;
}).RetryForever());
services.AddHttpClient("GreeterClient").AddPolicyHandlerFromRegistry("retryforever");
上面表示針對GreeterClient用戶端,增加一些retryforever的處理政策。
後面會介紹這種政策架子是如何實作的,在細節篇。
那通過Polic就可以針對不同場景,進行定義不同的政策,做出一些相應。看項目需求,這裡就不多介紹了,每個項目都不一樣。
結
下一節polly熔斷。