【发布时间】:2020-10-30 07:45:52
【问题描述】:
我正在评估Polly 库的功能和灵活性,作为评估过程的一部分,我尝试将WaitAndRetryPolicy 与BulkheadPolicy 策略结合起来,以实现弹性和节流的结合。问题是这种组合产生的行为不符合我的期望和偏好。我想要的是优先重试失败的操作,而不是执行新的/未处理的操作。
理由是(根据我的经验)失败的操作再次失败的可能性更大。因此,如果所有失败的操作都被推到整个过程的末尾,那么整个过程的最后一部分将非常缓慢且没有生产力。不仅因为这些操作可能再次失败,而且因为每次重试之间所需的延迟,在每次失败尝试后可能需要逐渐延长。所以我想要的是每次BulkheadPolicy 有空间开始一个新操作时,如果它的队列中有一个重试操作,则选择一个重试操作。
这是一个示例,演示了我想要修复的不良行为。需要处理 10 个项目。第一次尝试失败,第二次尝试成功,总共执行了 20 次。重试项目之前的等待时间为一秒。任何时候都应该只有 2 个操作处于活动状态:
var policy = Policy.WrapAsync
(
Policy
.Handle<HttpRequestException>()
.WaitAndRetryAsync(retryCount: 1, _ => TimeSpan.FromSeconds(1)),
Policy.BulkheadAsync(
maxParallelization: 2, maxQueuingActions: Int32.MaxValue)
);
var tasks = new List<Task>();
foreach (var item in Enumerable.Range(1, 10))
{
int attempt = 0;
tasks.Add(policy.ExecuteAsync(async () =>
{
attempt++;
Console.WriteLine($"{DateTime.Now:HH:mm:ss} Starting #{item}/{attempt}");
await Task.Delay(1000);
if (attempt == 1) throw new HttpRequestException();
}));
}
await Task.WhenAll(tasks);
输出(实际):
09:07:12 Starting #1/1
09:07:12 Starting #2/1
09:07:13 Starting #3/1
09:07:13 Starting #4/1
09:07:14 Starting #5/1
09:07:14 Starting #6/1
09:07:15 Starting #8/1
09:07:15 Starting #7/1
09:07:16 Starting #10/1
09:07:16 Starting #9/1
09:07:17 Starting #2/2
09:07:17 Starting #1/2
09:07:18 Starting #4/2
09:07:18 Starting #3/2
09:07:19 Starting #5/2
09:07:19 Starting #6/2
09:07:20 Starting #7/2
09:07:20 Starting #8/2
09:07:21 Starting #10/2
09:07:21 Starting #9/2
预期的输出应该是这样的(我手写的):
09:07:12 Starting #1/1
09:07:12 Starting #2/1
09:07:13 Starting #3/1
09:07:13 Starting #4/1
09:07:14 Starting #1/2
09:07:14 Starting #2/2
09:07:15 Starting #3/2
09:07:15 Starting #4/2
09:07:16 Starting #5/1
09:07:16 Starting #6/1
09:07:17 Starting #7/1
09:07:17 Starting #8/1
09:07:18 Starting #5/2
09:07:18 Starting #6/2
09:07:19 Starting #7/2
09:07:19 Starting #8/2
09:07:20 Starting #9/1
09:07:20 Starting #10/1
09:07:22 Starting #9/2
09:07:22 Starting #10/2
例如,在 09:07:14 标记处,失败的项目 #1 的 1 秒等待期已过期,因此它的第二次尝试应优先于对项目 #5 的第一次尝试。
解决这个问题的一个不成功的尝试是颠倒这两个策略的顺序。不幸的是,将BulkheadPolicy 放在WaitAndRetryPolicy 之前会降低并行化。发生的情况是BulkheadPolicy 将项目的所有重试视为单个操作,因此两次重试之间的“等待”阶段计入并行化限制。显然我不想那样。 documentation 也明确了我的示例中两个策略的顺序是正确的:
BulkheadPolicy:通常在最里面,除非包装了最终的TimeoutPolicy。当然在任何WaitAndRetry内。Bulkhead有意限制并行化。您希望并行化专门用于运行委托,而不是等待重试。
有什么方法可以实现我想要的行为,同时留在 Polly 库的领域?
【问题讨论】:
-
显然你不能开箱即用。我只需下载源代码并自己进行重载,然后发出拉取请求,或在 github 上请求该功能
-
@TheGeneral 是的,这是解决问题的缓慢、痛苦和费力的方法。我希望 Polly 库的一些有经验的用户知道一些简单的方法来解决它。
-
我每天都在使用它,但是我看不到直接的方法。也许其他人可以想到一个不合时宜的解决方案。祝你好运
-
@TheGeneral 谢谢!如果您有任何想法,请在 cmets 中分享。 :-)
标签: c# asynchronous parallel-processing polly