在 ActionBlock 中重新提交失败的任务

Re-Submitting a failed Task in an ActionBlock

我正在使用看起来像这样的操作块:

ActionBlock<Tuple<string,byte[],string>> ab  = 
    new ActionBlock<Tuple<string,string,string>>(item => {
            service.DoSomeAction(item.Item1, item.Item2, item.Item3);
        },
        new ExecutionDataflowBlockOptions {
            MaxDegreeOfParallelism = 2
        });

foreach(var item in Items) {
    ab.Post(new Tuple<string,string,string>(item.a, item.b, item.c));
}

ab.Complete();
ab.Completion.Wait();

我的问题是 service.DoSomeAction() 可能会因网络负载而失败,我想知道 ActionBlock 是否具有请求任务的机制。

我当然可以在该调用周围添加一个 try/catch 块,并在重新抛出异常之前让 catch 块 wait/retry 几次。我正在寻找的是用相同的参数调用 ab.Post() 。我的问题是我已经在调用 ab.Complete()。是否可以在不调用 ab.Complete() 的情况下等待 ActionBlock。我可以使用更好的工具来完成这项工作吗?

我不太了解ActionBlock,你能用Parallel class代替吗?

像这样:

Parallel.ForEach(Items, item =>
{
    bool succeeded = false;
    while(!succeeded)
    {
        try
        {
            service.DoSomeAction(item.Item1, item.Item2, item.Item3);
            succeeded = true;
        }
        catch(MyException) //the expected Exception, let others get thrown
        {
        }
    }
});

Is it possible to wait on an ActionBlock without calling ab.Complete().

是的,只是不要调用它,直接转到ab.Completion.Wait();旁注:如果可能,你应该使用await ab.Completion;),BUT 其他人将需要调用 ab.Complete(),否则它会无限期地等待,因为 ab.Completion 永远不会完成。

但是 为什么不想在操作中使用 "try/catch/retry" 逻辑? IMO 这将是更好的方法。
例如。使用 TransientFaultHandling.Core 你可以这样做:

var retry = new RetryPolicy(ErrorDetectionStrategy.On<Exception>(), // see http://pastebin.com/6tmQbkj4
                            3, TimeSpan.FromMilliseconds(250));     
ActionBlock<Tuple<string,byte[],string>> ab  = 
    new ActionBlock<Tuple<string,string,string>>(item => 
        retry.ExecuteAction(() => service.Action(item.Item1, item.Item2, item.Item3)),
        new ExecutionDataflowBlockOptions {
            MaxDegreeOfParallelism = 2
        });