在非常基本的情况下,我使用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并不是问题。
答案 0 :(得分:1)
在 HttpClient
内使用Polly 效果不佳。单个SendAsync
旨在成为单个呼叫。即:
HttpClient
超时都将应用于单个SendAsync
呼叫。HttpClient
的某些版本也会处理其内容,因此不能
在下一个SendAsync
调用中被重用。底线:覆盖SendAsync
非常适合添加请求前和请求后逻辑。这不是重试的正确位置。
相反,请使用常规的HttpClient
,并让您的Polly逻辑在GetStringAsync
(或其他任何调用)的外部中重试。