Повторите попытку несколько раз, когда истечет время ожидания HTTP-запроса, используя polly c #

Мое первоначальное намерение состояло в том, чтобы повторить попытку несколько раз по истечении времени ожидания самого запроса, например, при попытке связаться с другой микрослужбой, которая не работает на пару секунд в надежде, что это временный сбой. Если есть более простое решение, этого будет достаточно. Я решил вручную установить тайм-аут для каждой попытки, используя политику упаковки, надеясь достичь того же результата.

Я видел подобное решение, не использующее httpclientfactory здесь Использовать определенный тайм-аут подключен к повторной политике, но у меня это не работает.

Мой код выглядит так:

services.AddHttpClient("retryclient", client =>
{
    client.Timeout = TimeSpan.FromSeconds(100);
}).AddPolicyHandler((servs, request) =>
    Policy.HandleResult<HttpResponseMessage>(r =>
        {
            return r.StatusCode == HttpStatusCode.NotFound; //(1)
        }).
.OrTransiesntHttpError().
WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
    onRetry: (exception, timespan, retryAttempt, context) =>
        { // using servs to log // });
}).WrapAsync(Policy.TimeoutAsync(1)));

Я проверил, что политика повторных попыток работает, когда я пытаюсь получить доступ к «ненайденному» адресу, не оборачивая политику тайм-аута, и она работает нормально. Я также пробовал использовать строку (1) с кодом состояния HttpStatusCode.RequestTimeout вместо не найдено для моего случая, но это не работает.

Когда я использую упаковку и пытаюсь получить доступ к сервису, который не работает, он выдает Polly.Timeout.TimeoutRejectedException с первой попытки, как я и ожидал, но больше не пытается. Я не мог придумать способ повторить попытку несколько раз, либо с установленным таймаутом для каждой попытки, либо только тогда, когда время ожидания самого запроса истекает без использования политики тайм-аута.

Изменить: после дальнейшего чтения https://cm.engineering/transient-timeouts-and-the-retry-rabbit-hole-net-4-5-f406cebbf194, похоже, моя проблема заключается в обработке политики. У меня нет доступа к токену отмены HttpClient. Я предполагаю, что могу исправить это, переопределив метод sendAsync, как показано в ссылке. Есть ли элегантный способ сделать то же самое при создании фабрики?


person pixel    schedule 26.04.2020    source источник


Ответы (1)


Документация Polly на HttpClientFactory охватывает это в разделе, помеченном применение тайм-аутов:

Вы можете захотеть, чтобы политика повтора повторяла попытку, если истекло время ожидания какой-либо отдельной попытки. Для этого сделайте так, чтобы политика повтора обрабатывала TimeoutRejectedException, который генерирует политика тайм-аута Полли.

So:

services.AddHttpClient("retryclient", client =>
{
    client.Timeout = TimeSpan.FromSeconds(100);
}).AddPolicyHandler((servs, request) =>
    Policy.HandleResult<HttpResponseMessage>(r =>
        {
            return r.StatusCode == HttpStatusCode.NotFound; //(1)
        }).
.OrTransientHttpError()
.Or<TimeoutRejectedException>() // ** ADDED **
.WaitAndRetryAsync(5, retryAttempt => TimeSpan.FromSeconds(retryAttempt),
    onRetry: (exception, timespan, retryAttempt, context) =>
        { // using servs to log // });
})
.WrapAsync(Policy.TimeoutAsync(1)));

Полли правильно передает CancellationToken внутреннему вызову .SendAsync(); в этом нет необходимости вносить какие-либо изменения.

person mountain traveller    schedule 02.05.2020
comment
Обратите внимание, что если тайм-аут клиента слишком близок к тайм-ауту политики, он все равно может дать сбой и больше не повторить попытку. Я не уверен, почему это происходит, но я мог просто установить тайм-аут клиента на достаточно большое число, и это сработало для меня. - person pixel; 03.05.2020
comment
Согласовано: это описано в документации, в которой говорится: HttpClient.Timeout будет применяться в качестве общего тайм-аута для каждого всего вызова через HttpClient, включая все попытки и ожидания между повторными попытками. - person mountain traveller; 04.05.2020