下游块中的TPL数据流和异常处理

时间:2017-09-07 20:12:39

标签: c# exception-handling task-parallel-library tpl-dataflow

我有以下伪代码:

var queue = new BufferBlock<int>(new DataflowBlockOptions { BoundedCapacity = 5 });
var a = new ActionBlock<int>(async item =>
    {
        await Task.Delay(500);
        Trace.TraceInformation(
            $"Target 1: | Type: {typeof(int).Name} | Thread: {Thread.CurrentThread.ManagedThreadId} | Message: {item}");
        // handling some logic but it throws
        if (item >= 5) throw new Exception("Something bad happened");

    }, new ExecutionDataflowBlockOptions { BoundedCapacity = 1, MaxDegreeOfParallelism = 1 });

queue.LinkTo(a, new DataflowLinkOptions { PropagateCompletion = true });

var targets = new List<ITargetBlock<int>> {queue};

var broadcaster = new ActionBlock<int>(
    async item =>
    {
        var processingTasks = targets.Select(async t =>
        {
            try
            {
                // This is condition is always false
                // t (bufferblock) has no exceptions. Exception is raised in downstream action block where it sends to
                if (!await t.SendAsync(item))
                    await t.Completion;
            }
            catch (Exception e)
            {
                Trace.TraceInformation("Handled exception : " + e.Message);
            }
        });

        try
        {
            // Neither here the exception is rethrowed
            await Task.WhenAll(processingTasks);
        }
        catch (Exception e)
        {
            Trace.TraceInformation("Handled exception WhenAll : " + e.Message);
        }
    });

for (var i = 1; i <= 10; i++)
{
    broadcaster.Post(i);
}

管道的配置与ActionBlock<int> => BufferBlock<int> => ActionBlock<int>类似。

最后一个ActionBlock<int>抛出一个异常,但是我想要处理它的源块不会被重新抛出。

如何重写此代码以便正确处理异常?

1 个答案:

答案 0 :(得分:4)

您可以找到此主题的官方指南here。总体解决方案是订阅所有块Completion任务并检查其状态,并在需要时替换故障块(一个应该存储块的所有引用)。有关更多信息,请参阅整篇文章。

  

Faulted阻止

的网络行为      
      
  1. 预留消息
      为了避免消息损坏,出现故障的块应清除其消息队列并进入Faulted状态   尽快地。有一种情况不遵守   此规则:包含目标保留的消息的源块。   如果遇到内部异常的块有一条消息   由目标保留,保留的消息不得为   已删除,并且该块不应移至Faulted状态   直到消息被释放或消费。

  2.   
  3. 悬挂网络
      ...

         
        
    • 保留对网络中所有块的引用,并使用Task.WaitAllTask.WhenAll等待它们(同步或   异步)。如果块发生故障,其Completion任务将会发生   在Faulted州完成。
    •   
    • 构建线性网络时,DataflowLinkOptionsPropagateCompletion == true一起使用。这将传播块完成   来源目标。在这种情况下,在网络上等待就足够了   叶块。
    •   
  4.