微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

在我的应用中,我使用 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(在 .NET 5 中为 HttpRequestMessage.Options)。像这样:

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

...

var httpResponse = ...
var responseContent = ...
if (InternalServerResponse(responseContent))
{
    httpResponse.RequestMessage.Properties[IsInternalServerResponseKey] = true;
}

通过这种方式,请求/响应附加了一个标志,可以被代码的其他部分读取,特别是 Polly 重试处理程序。

解决方案的另一部分是重试次数。通常,Polly 具有确定是否应该重试的委托,并且这些委托是独立的——重试这种类型的异常,或者重试类似的响应。在这种情况下,您想重试匹配特定形状的响应仅当重试次数不多,并且重试次数过多并且响应与“重试”形状匹配时,那么您不想抛出异常而是返回响应。

这是不寻常的,但可行。您需要在 Polly 上下文中捕获“外部注意事项”(在本例中为重试计数)。然后您的重试委托可以从上下文中提取重试计数并以此为基础做出决定。这样的事情应该可以工作:

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);
}

我还没有测试过;传递给 2WaitAndRetryAsync 和用于比较 2retryCount 之间可能存在一对一错误。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。