В общем, вы можете настроить политики Polly для реагирования на результаты выполнения (не только исключения), например, проверить HttpResponseMessage.StatusCode
с помощью предиката.Примеры здесь, в файле readme Polly .
Однако нет встроенного встроенного способа настройки политики single Polly для дополнительного ответа на содержимое ответного сообщения.Это происходит потому, что (как показывает ваш пример) получение этого контента требует второго асинхронного вызова, который сам может вызвать сетевые ошибки.
Это tl; dr создает сложности в отношении того, как выразить (в простом синтаксисе) одну политику, которая управляет двумя различными асинхронными шагами с потенциально различной обработкой ошибок для каждого шага.Предыдущее соответствующее обсуждение на Polly github : комментарии приветствуются.
Таким образом, когда для последовательности требуется два отдельных асинхронных вызова, команда Polly в настоящее время рекомендует выразить это как две отдельные политики, аналогичные пример в конце этого ответа .
Конкретный пример в вашем вопросе может не сработать, поскольку делегат onRetryAsync
(выбрасывающий FlakyApiException
) сам не защищен политикой,Политика только защищает выполнение делегатов, выполняемых с помощью .Execute/ExecuteAsync(...)
.
. Один из подходов может заключаться в использовании двух политик: политики повторных попыток, которая повторяет все типичные исключения http и коды состояния, включая 500;затем внутри этого Polly FallbackPolicy , который перехватывает код состояния 500, представляющий SqlDateTime overflow
, и исключает его повторную попытку путем повторного вызова в качестве некоторого отличительного исключения (CustomSqlDateOverflowException
).
IAsyncPolicy<HttpResponseMessage> rejectSqlError = Policy<HttpResponseMessage>
.HandleResult(r => r.StatusCode == HttpStatusCode.InternalServerError)
.FallbackAsync(async (delegateOutcome, context, token) =>
{
String stringContent = await delegateOutcome.Result.Content.ReadAsStringAsync(); // Could wrap this line in an additional policy as desired.
if (delegateOutcome.Result.StatusCode == HttpStatusCode.InternalServerError && stringContent.Contains("SqlDateTime overflow"))
{
throw new CustomSqlDateOverflowException(); // Replace 500 SqlDateTime overflow with something else.
}
else
{
return delegateOutcome.Result; // render all other 500s as they were
}
}, async (delegateOutcome, context) => { /* log (if desired) that InternalServerError was checked for what kind */ });
IAsyncPolicy<HttpResponseMessage> retryPolicy = Policy<HttpResponseMessage>
.Handle<HttpRequestException>()
.OrResult(r => r.StatusCode == HttpStatusCode.InternalServerError)
.OrResult(r => /* condition for any other errors you want to handle */)
.WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
async (exception, timeSpan, context) =>
{
/* log (if desired) retry being invoked */
});
HttpResponseMessage response = await retryPolicy.WrapAsync(rejectSqlError)
.ExecuteAsync(() => client.PostAsync(requestUri, new StringContent(serialisedParameters, Encoding.UTF8, "application/json"), cancellationToken));