前言
簡單整理一下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熔斷。