c# - 如何使用 Polly 根据响应内容重试 x 次,然后返回响应?

标签 c# .net-core polly

在我的应用程序中,我使用 Polly调用 API 的库。
API 可以在响应中返回警告和错误。对于其中一些警告,我想重试 2 次,下一次我想 将响应返回给调用者 .
这可以做到吗?
编辑:
@StephenCleary 指出我应该只处理响应而不抛出异常。
要检查响应,我需要等待内容。以下将无法编译,任何人都可以看到我该怎么做吗?

static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
            .HandleTransientHttpError()
            .OrResult(async msg =>
            {
               var content  = await msg.Content.ReadAsStringAsync();
               return content.Contains("errorcode123");
            })
            .WaitAndRetryAsync(2, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)));
}

最佳答案

这有几个部分。
首先,如果结果有警告,你不想抛出异常。那时也许你想重试,也许你不想;那里的代码还不能说。但是抛出异常意味着响应被丢弃,所以此时抛出是​​不正确的。
相反,该处理程序应使用“有警告”标志标记响应。这可以使用 HttpRequestMessage.Properties (HttpRequestMessage.Options 在 .NET 5 中)。像这样的东西:

private static readonly string IsInternalServerResponseKey = Guid.NewGuid().ToString("N");

...

var httpResponse = ...
var responseContent = ...
if (InternalServerResponse(responseContent))
{
    httpResponse.RequestMessage.Properties[IsInternalServerResponseKey] = true;
}
这样,请求/响应就会附加一个标志,代码的其他部分可以读取该标志,特别是 Polly 重试处理程序。
解决方案的另一部分是重试计数。通常,Polly 具有决定是否应该重试的委托(delegate),并且这些委托(delegate)是自包含的 - 重试这种类型的异常,或重试类似的响应。在这种情况下,您想重试匹配特定形状的响应,但前提是重试次数不多,并且如果重试次数过多并且响应匹配“重试”形状,那么您不希望抛出异常但返回响应。
这是不寻常的,但可行的。您需要在 Polly 上下文中捕获“外部注意事项”(在本例中为重试计数)。然后,您的重试委托(delegate)可以从上下文中提取重试计数并以此为基础做出决定。像这样的东西应该工作:
private static readonly string RetryCountKey = Guid.NewGuid().ToString("N");
static IAsyncPolicy<HttpResponseMessage> GetRetryPolicy()
{
    return HttpPolicyExtensions
        .HandleTransientHttpError()
        .OrResult(response =>
        {
            return IsInternalServerResponse() && RetryCount() <= 2;

            bool IsInternalServerResponse()
            {
                if (!response.RequestMessage.Properties.TryGetValue(IsInternalServerResponseKey, out var objValue) ||
                    objValue is not bool boolValue)
                    return false;
                return boolValue;
            }

            int RetryCount()
            {
                if (!response.RequestMessage.GetPolicyExecutionContext().TryGetValue(RetryCountKey, out var objValue) ||
                    objValue is not int intValue)
                    return 0;
                return intValue;
            }
        })
        .WaitAndRetryAsync(2,
            (retryAttempt, _) => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
            (_, _, retryAttempt, context) => context[RetryCountKey] = retryAttempt);
}
我没有测试过这个; 2 之间可能存在一个错误。传递给 WaitAndRetryAsync2用于比较 retryCount .

关于c# - 如何使用 Polly 根据响应内容重试 x 次,然后返回响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67386496/

相关文章:

c# - 更改带有选项卡的接受按钮

c# - 在 ASP .NET Core 中自动递增版本号

c# - 图片格式未知

c# - Polly HandleTransientHttpError 没有捕捉到 HttpRequestException

c# - 为什么 File.ReadAllLinesAsync() 会阻塞 UI 线程?

c# - 如何将短网址重定向到更具描述性的长网址

c# - 用神经网络求解 Y = X * X + b 型公式

model-view-controller - 403 - 禁止 : Access is denied. ASP.NET Core MVC IIS 客户端证书 SSL

c# - Polly RetryForever 没有重试

c# - 将策略定义与执行分开时了解 Polly 策略的语义