简体   繁体   English

Polly 不会抛出一些异常?

[英]Polly won't throw on some exceptions?

I'm using Polly with .net Core.我将 Polly 与 .net 核心一起使用。 My ConfigureServices is:我的ConfigureServices是:

private static void ConfigureServices()
{
    var collection = new ServiceCollection();
    var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(3);  
    collection.AddHttpClient<INetworkService, NetworkService>(s=>
             {
                   s.BaseAddress = new Uri("http://google.com:81"); //this is a deliberate timeout url
             })
    .AddPolicyHandler((a,b)=>GetRetryPolicy(b))
    .AddPolicyHandler(timeoutPolicy); ;
    ...
}

This is the GetRetryPolicy function:这是GetRetryPolicy function:

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(HttpRequestMessage req)
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(msg => httpStatusCodesWorthRetrying.Contains(msg.StatusCode))  // see below
        .Or<TimeoutRejectedException>()
        .Or<TaskCanceledException>()
        .Or<OperationCanceledException>()
        .WaitAndRetryAsync(3, retryAttempt =>
        {
            return TimeSpan.FromSeconds(3);
        }, onRetry: (response, delay, retryCount, context) =>
        {

            Console.WriteLine($"______PollyAttempt_____ retryCount:{retryCount}__FOR_BaseUrl_{req.RequestUri.ToString()}");
        });
}

Those are the httpcodes I want to retry:这些是我想重试的httpcode:

static HttpStatusCode[] httpStatusCodesWorthRetrying = {
   HttpStatusCode.RequestTimeout, // 408
   HttpStatusCode.InternalServerError, // 500
   HttpStatusCode.BadGateway, // 502
   HttpStatusCode.ServiceUnavailable, // 503
   HttpStatusCode.GatewayTimeout // 504
};

Ok.好的。 And this is the actual invocation:这是实际的调用:

public async Task Work()
    {

        try
        {
            
            HttpResponseMessage response = await _httpClient.GetAsync("");
            Console.WriteLine("After work");

        }
        catch (TimeoutRejectedException ex)
        {
            Console.WriteLine("inside TimeoutRejectedException");
        }

        catch (Exception ex)
        {
            Console.WriteLine("inside catch main http");
        }
}

The output is: output 是:

_ PollyAttempt retryCount:1__FOR_BaseUrl_ http://google.com:81/ _ PollyAttempt retryCount:1__FOR_BaseUrl_ http://google.com:81/
_ PollyAttempt retryCount:2__FOR_BaseUrl_ http://google.com:81/ _ PollyAttempt retryCount:2__FOR_BaseUrl_ http://google.com:81/
_ PollyAttempt retryCount:3__FOR_BaseUrl_ http://google.com:81/ _ PollyAttempt retryCount:3__FOR_BaseUrl_ http://google.com:81/
inside TimeoutRejectedException TimeoutRejectedException 内部

(notice it throws) Which is OK. (注意它抛出)没关系。 Because Polly throws after this invalid URL is timeout.因为 Polly 在这个无效的 URL 超时后抛出。

But if I change the http://google.com:81/ to an "internal server error" url: (this return 500)但是,如果我将http://google.com:81/更改为“内部服务器错误”url:(返回 500)

https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148

Then it doesn't throw but continues:然后它不会抛出,而是继续:

_ PollyAttempt retryCount:1__FOR_BaseUrl_ https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148 _ PollyAttempt retryCount:1__FOR_BaseUrl_ https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
_ PollyAttempt retryCount:2__FOR_BaseUrl_ https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148 _ PollyAttempt retryCount:2__FOR_BaseUrl_ https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
_ PollyAttempt retryCount:3__FOR_BaseUrl_ https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148 _ PollyAttempt retryCount:3__FOR_BaseUrl_ https://run.mocky.io/v3/9f1b4c18-2cf0-4303-9136-bb67d54d0148
After work下班以后

(notice "after work" at the end) (最后注意“下班后”)

Question:问题:

Why does Polly throw at timeout, But doesn't throw at another condition?为什么 Polly 在超时时抛出,但在其他条件下不抛出? I explictly wrote: .OrResult(msg => httpStatusCodesWorthRetrying.Contains(msg.StatusCode)) and 500 is one of them.我明确写道: .OrResult(msg => httpStatusCodesWorthRetrying.Contains(msg.StatusCode))而 500 就是其中之一。

As @StephenCleary said that's how the Polly works.正如@StephenCleary 所说,Polly 就是这样工作的。

First let me share with you the cleaned up version of your code首先让我与您分享您的代码的清理版本
then I will give you some explanation about the observed behaviours.然后我会给你一些关于观察到的行为的解释。

ConfigureServices

var timeoutPolicy = Policy.TimeoutAsync<HttpResponseMessage>(3,
    onTimeoutAsync: (_, __, ___) => {
        Console.WriteLine("Timeout has occured");
        return Task.CompletedTask;
});

services.AddHttpClient<INetworkService, NetworkService>(
    client => client.BaseAddress = new Uri("https://httpstat.us/500"))
.AddPolicyHandler((_, request) => Policy.WrapAsync(GetRetryPolicy(request), timeoutPolicy));

GetRetryPolicy

private static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy(HttpRequestMessage req)
    => HttpPolicyExtensions
        .HandleTransientHttpError()
        .Or<TimeoutRejectedException>()
        .Or<OperationCanceledException>()
        .WaitAndRetryAsync(3,
            _ => TimeSpan.FromSeconds(3),
            onRetry: (_, __, retryCount, ___) =>
                Console.WriteLine($"POLLY retryCount:{retryCount} baseUrl: {req.RequestUri}"));

Example http://google.com:81示例http://google.com:81

  1. Initial request has been sent out初始请求已发出
  2. No response has been received under 3 seconds 3秒内未收到回复
  3. Timeout Policy triggered已触发超时策略
  4. TimeoutRejectedException is thrown抛出TimeoutRejectedException
  5. Retry policy is aware of that exception, so it triggers重试策略知道该异常,因此它会触发
  6. Retry policy issues 3 seconds penalty重试策略问题 3 秒惩罚
  7. Retry policy issues a new request重试策略发出新请求
  8. No response has been received under 3 seconds 3秒内未收到回复
  9. ... ...
    n. n. Retry policy is aware of that exception, but it has reached the max retry count重试策略知道该异常,但已达到最大重试次数
    n+1. n+1。 Retry throws the exception that it could not handle, so in this case the TimeoutRejectedException重试抛出它无法处理的异常,所以在这种情况下TimeoutRejectedException

Example https://httpstat.us/500示例https://httpstat.us/500

  1. Initial request has been sent out初始请求已发出
  2. A response with status code 500 has received under 3 seconds在 3 秒内收到状态代码为 500 的响应
  3. Retry policy is aware of that status code, so it triggers重试策略知道该状态代码,因此它会触发
  4. Retry policy issues 3 seconds penalty重试策略问题 3 秒惩罚
  5. Retry policy issues a new request重试策略发出新请求
  6. response with status code 500 has received under 3 seconds在 3 秒内收到状态码为 500 的响应
  7. ... ...
    n. n. Retry policy is aware of that status code, but it has reached the max retry count重试策略知道该状态代码,但已达到最大重试次数
    n+1. n+1。 Retry returns with that response that it could not handle, so in this case the 500重试返回它无法处理的响应,所以在这种情况下 500

Because there is a lack of EnsureSuccessStatusCode method call that's why no exception is being thrown.因为缺少EnsureSuccessStatusCode方法调用,所以没有抛出异常。

As you can see in the second example the TimeoutPolicy is not triggered at all.正如您在第二个示例中看到的那样,TimeoutPolicy 根本没有被触发。

This is expected behavior.这是预期的行为。 A delegate invocation results in either an exception or a return value.委托调用会导致异常或返回值。 When the Polly retries are done, then it propagates whatever result was last, whether it is an exception or a return value.当 Polly 重试完成时,它会传播最后的结果,无论是异常还是返回值。

In this case, the response would have a 500 status code.在这种情况下,响应将具有 500 状态代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM