重试后,Polly WaitandRetrysync悬挂



如果HTTP调用失败,我在非常基本的情况下使用Polly进行指数退回:

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>();
}

我有一个仅在while(true)中创建HttpListener并循环的测试API。目前,我正在尝试测试客户在每个呼叫中接收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不是问题。

HttpClient中使用polly 使用效果不佳。单个SendAsync旨在单个呼叫。即:

  • 任何HttpClient超时都将适用于单个SendAsync调用。
  • HttpClient的某些版本也会处理其内容,因此不能在下一个SendAsync呼叫中重复使用。
  • 如评论中指出的这种悬挂是已知的问题,不能是由Polly确定。

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

相反,请使用常规HttpClient,并使您的Polly Logic Retry exife GetStringAsync(或其他(调用。

这似乎是.NET框架已知问题并在HTTPClient中使用Polly的合适解决方法。我们必须在重试时处置结果,以允许多个请求。请参阅此处有关原始问题的讨论,以及另一个描述解决方法的讨论。我只是对此进行了简短的测试以确定它有效,但尚未完全研究可能存在哪些副作用。

Policy
.Handle<HttpRequestException>()
.OrResult<HttpResponseMessage>(msg => RetryableStatusCodesPredicate(msg.StatusCode))
.RetryAsync(retryCount, onRetry: (x, i) =>
{
    x.Result.Dispose(); // workaround for https://github.com/aspnet/Extensions/issues/1700
}));

相关内容

  • 没有找到相关文章

最新更新