如何在通过Polly重试策略执行的委托中获取重试计数?

13

我正在我的C# web应用程序中使用Polly来重试请求。 我的示例代码包含在此帖子中。 代码按预期工作,但传递给CreateFile()的最后一个参数(当前硬编码为0)需要是retryAttempt的值。 如何在Execute的Action中获取retryAttempt的值?

return Policy
    .Handle<HttpException>(x => x.StatusCode == (HttpStatusCode)429)
    .Or<StorageException>()
    .WaitAndRetry(maxRetryCount, retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(retryIntervalMs, retryAttempt)))
    .Execute(() => CreateFile(fileContent, containerName, fileName, connectionString, 0));

请注意,Polly具有一些特定的重试重载,可帮助处理429响应,如果429响应指定了等待时间。可以使重试策略等待429响应中指定的确切重试后持续时间。 - mountain traveller
1个回答

18

Polly没有提供一个重试次数是委托参数之一的.Execute(...)重载。这是因为重试只是众多Polly策略中的一种,而.Execute(...)重载的形式必须适用于所有策略类型。

对于问题描述的用例,简单地:

int count = 0;
return Policy
    .Handle<HttpException>(x => x.StatusCode == (HttpStatusCode)429)
    .Or<StorageException>()
    .WaitAndRetry(maxRetryCount, retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(retryIntervalMs, retryAttempt)))
    .Execute(() => CreateFile(fileContent, containerName, fileName, connectionString, count++));

一种替代方法是使用Polly的执行作用域Polly.Context:其中的实例随着每次执行而传递,并且可供执行的所有部分使用。
重试策略已经将重试计数传递给onRetry委托,因此该策略可以将其捕获到执行作用域的Context中:
var retryPolicyCapturingCountIntoContext =
    Policy
        .Handle<HttpException>(x => x.StatusCode == (HttpStatusCode)429)
        .Or<StorageException>()
        .WaitAndRetry(
            maxRetryCount,
            retryAttempt => TimeSpan.FromMilliseconds(Math.Pow(retryIntervalMs, retryAttempt)),
            onRetry: (response, delay, retryCount, context) =>
            {
                context["retrycount"] = retryCount;
            });

透过策略执行的委托,我们可以从Context中挑选出重试次数(需要特别小心处理还没有发生重试的情况):

retryPolicyCapturingCountIntoContext
    .Execute(context =>
    {
        int retryCount = (context.TryGetValue("retrycount", out var retryObject) && retryObject is int count) ? count : 0;
        CreateFile(fileContent, containerName, fileName, connectionString, retryCount);
    }, new Context());

如果你想避免 context.TryGetValue(...) 防御性代码的干扰,你可以选择在启动执行之前始终初始化 context["retrycount"]

var myContext = new Polly.Context { {"retrycount ", 0} };
retryPolicyCapturingCountIntoContext
    .Execute(
         context => CreateFile(fileContent, containerName, fileName, connectionString, (int)context["retrycount"]),
         myContext);

对于想要记录每个重试的重试计数(例如用于日志),可以参考Polly重试示例,其中展示了如何将retryCount作为输入参数传递给可以在策略上配置的onRetry委托。更多示例请参见此处
对于想要以一种通用的方式捕获操作使用的总重试次数以便成功,例如用于某些常规执行-调度基础架构代码的遥测,请参阅Steve Gordon博客中的这些示例,这些示例使用基于Context的方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接