在尝试使用Polly之前,请检查响应的字符串内容 [英] Check string content of response before retrying with Polly

查看:100
本文介绍了在尝试使用Polly之前,请检查响应的字符串内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用非常不稳定的API.有时我将500 Server ErrorTimeout结合使用,有时我也得到了500 Server Error,因为我给它输入了无法处理SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.的输入.

I'm working with a very flaky API. Sometimes I get 500 Server Error with Timeout, some other time I also get 500 Server Error because I gave it input that it can't handle SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM..

这两种情况都给我HttpRequestException,但是我可以调查服务器的回复消息并确定异常原因.如果是超时错误,我应该再试一次.如果输入内容不正确,我应该重新抛出异常,因为没有重试次数可以解决数据错误的问题.

Both of these cases give me HttpRequestException but I can look into the reply message from the server and determine the cause of the exception. If it is a timeout error, I should try again. If it is a bad input I should re-throw the exception, because no amount of retries will fix the problem of bad data.

我想对Polly进行的操作是在尝试重试之前检查响应消息.但是到目前为止,我所看到的所有样本都只包含异常类型.

What I'd like to do with Polly is to check on response message before attempting to retry. But all the samples I've seen so far only included type of exception.

到目前为止,我已经提出了这个建议:

I've come up with this so far:

        HttpResponseMessage response = null;
        String stringContent = null;
        Policy.Handle<FlakyApiException>()
             .WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
              async (exception, timeSpan, context) =>
            {
                response = await client.PostAsync(requestUri, new StringContent(serialisedParameters, Encoding.UTF8, "application/json"));
                stringContent = await response.Content.ReadAsStringAsync();

                if (response.StatusCode == HttpStatusCode.InternalServerError && stringContent.Contains("Timeout"))
                {
                    throw new FlakyApiException(stringContent);
                }
            });

有没有更好的方法来进行这种检查?

Is there a better way to do this kind of checking?

推荐答案

通常,您可以配置Polly策略以响应执行结果(不仅仅是异常),例如,使用谓词检查HttpResponseMessage.StatusCode .示例此处位于Polly自述文件.

In general, you can configure Polly policies to respond to the results of an execution (not just an exception), for example check an HttpResponseMessage.StatusCode with a predicate. Examples here in the Polly readme.

但是,没有一种内置方式可以配置 Polly策略来另外响应响应消息的 content .这是因为(如您的示例所示)获取内容需要第二次异步调用,这本身可能会引发网络错误.

There is not however an in-built way to configure a single Polly policy to respond additionally to the content of the response message. This is because (as your example shows) obtaining that content requires a second async call, which may itself raise network errors.

tl; dr 带来了有关如何表达(以简单的语法)单个策略的麻烦,该策略管理两个不同的异步步骤,每个步骤可能具有不同的错误处理.先前在Polly github上的相关讨论 :欢迎发表评论.

This tl;dr engenders complications about how to express (in a simple syntax) a single policy which manages two different async steps with potentially different error handling for each step. Prior related discussion on Polly github: comment welcome.

因此,在一个序列需要两个单独的异步调用的情况下,Polly小组目前建议将此表示为两个单独的策略,类似于

As such, where a sequence requires two separate async calls, the Polly team currently recommends expressing this as two separate policies, similar to the example in the end of this answer.

您问题中的特定示例可能无法正常工作,因为onRetryAsync委托(引发FlakyApiException)本身不受策略保护.策略仅保护通过.Execute/ExecuteAsync(...)执行的委托的执行.

The particular example in your question may not work because the onRetryAsync delegate (throwing FlakyApiException) is not itself guarded by the policy. A policy only guards the execution of delegates executed through .Execute/ExecuteAsync(...).

一种方法可能是使用两种策略,一种重试策略可重试所有典型的http异常和状态码(包括500s);然后在其中一个Polly FallbackPolicy 中,该陷阱会捕获表示SqlDateTime overflow的状态代码500,并排除了通过重新抛出作为某些区别性异常(CustomSqlDateOverflowException)进行重试的可能性.

One approach could be to use two policies, a retry policy which retries all typical http exceptions and status codes including 500s; then inside that a Polly FallbackPolicy which traps the status code 500 representing SqlDateTime overflow, and excludes that from being retried by rethrowing as some distinguishing exception (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));

这篇关于在尝试使用Polly之前,请检查响应的字符串内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆