我在非常基本的场景中使用 Polly 做指数退避(exponential backoff),以便在 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,它只创建了一个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的问题。
ConfigureAwait(false)
来等待HandleTransientHttpError()
。 - Theodor Zoulias