重试一次后,Polly WaitAndRetryAsync挂起

时间:2019-06-26 09:15:08

标签: c# .net polly

在非常基本的情况下,我使用Polly在HTTP调用失败的情况下进行指数补偿:

protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    return await HandleTransientHttpError()
        .Or<TimeoutException>()
        .WaitAndRetryAsync(4, retryAttempt => TimeSpan.FromSeconds(Math.Pow(3, retryAttempt)))
        .ExecuteAsync(async () => await base.SendAsync(request, cancellationToken).ConfigureAwait(false));
}

private static PolicyBuilder<HttpResponseMessage> HandleTransientHttpError()
{
    return Policy
        .HandleResult<HttpResponseMessage>(response => (int)response.StatusCode >= 500 || response.StatusCode == System.Net.HttpStatusCode.RequestTimeout)
        .Or<HttpRequestException>();
}

我有一个测试API,该API仅创建HttpListener并在while(true)中循环。当前,我正在尝试测试客户端在每次收到500个电话时是否正确重试。

while (true)
{
    listener.Start();
    Console.WriteLine("Listening...");
    HttpListenerContext context = listener.GetContext();
    HttpListenerRequest request = context.Request;

    HttpListenerResponse response = context.Response;
    response.StatusCode = (int)HttpStatusCode.InternalServerError;

    //Thread.Sleep(1000 * 1);
    string responseString = "<HTML><BODY> Hello world!</BODY></HTML>";
    byte[] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
    response.ContentLength64 = buffer.Length;
    System.IO.Stream output = response.OutputStream;
    output.Write(buffer, 0, buffer.Length);
    output.Close();
    listener.Stop();
}

使用上述代码,所有代码都可以正常运行,并且分别在等待3、9、27和81秒后重试。

但是,如果我取消对Thread.Sleep调用的注释,客户端将重试一次,然后挂起,直到该呼叫对其他3次重试超时为止。

实际的生产API也会发生同样的事情,这使我相信测试API并不是问题。

1 个答案:

答案 0 :(得分:1)

HttpClient内使用Polly 效果不佳。单个SendAsync旨在成为单个呼叫。即:

  • 任何HttpClient超时都将应用于单个SendAsync呼叫。
  • HttpClient的某些版本也会处理其内容,因此不能 在下一个SendAsync调用中被重用。
  • 如评论中所述, 这种挂起是known issue,不能 由Polly修复。

底线:覆盖SendAsync非常适合添加请求前和请求后逻辑。这不是重试的正确位置。

相反,请使用常规的HttpClient,并让您的Polly逻辑在GetStringAsync(或其他任何调用)的外部中重试。