Polly WaitAndRetryAsync зависает после одной попытки - PullRequest
0 голосов
/ 26 июня 2019

Я использую Полли в очень простом сценарии для экспоненциального отката в случае сбоя 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.

1 Ответ

1 голос
/ 26 июня 2019

Использование Polly в HttpClient работает не очень хорошо.Один SendAsync предназначен для одного вызова.Т.е.:

  • Любые тайм-ауты HttpClient будут применяться к одиночному вызову SendAsync.
  • Некоторые версии HttpClient также располагают своим контентом, поэтому его нельзя использовать повторно.в следующем SendAsync вызове.
  • Как отмечено в комментариях, этот тип зависания является известной проблемой и не может быть исправлен Полли.

Итог: переопределение SendAsync отлично подходит для добавления логики перед запросом и после запроса.Это не подходящее место для повторной попытки.

Вместо этого используйте обычный HttpClient, и пусть ваша логика Polly повторяет за пределами GetStringAsync (или любого другого) вызова.

...