我有以下伪代码:
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>
抛出一个异常,但是我想要处理它的源块不会被重新抛出。
如何重写此代码以便正确处理异常?
答案 0 :(得分:4)
您可以找到此主题的官方指南here。总体解决方案是订阅所有块Completion
任务并检查其状态,并在需要时替换故障块(一个应该存储块的所有引用)。有关更多信息,请参阅整篇文章。
的网络行为
Faulted
阻止
预留消息
为了避免消息损坏,出现故障的块应清除其消息队列并进入Faulted
状态 尽快地。有一种情况不遵守 此规则:包含目标保留的消息的源块。 如果遇到内部异常的块有一条消息 由目标保留,保留的消息不得为 已删除,并且该块不应移至Faulted
状态 直到消息被释放或消费。- 醇>
悬挂网络
...
- 保留对网络中所有块的引用,并使用
Task.WaitAll
或Task.WhenAll
等待它们(同步或 异步)。如果块发生故障,其Completion
任务将会发生 在Faulted
州完成。- 构建线性网络时,
DataflowLinkOptions
与PropagateCompletion == true
一起使用。这将传播块完成 来源目标。在这种情况下,在网络上等待就足够了 叶块。