Bug*_*ter 10 c# error-handling tpl-dataflow
我正在设计一个由多个块组成的长时间运行的Dataflow管道.项目被输入到管道的输入块,最终通过它,并在最后的UI中显示(作为对用户的礼貌 - 管道的真正工作是将处理结果保存到磁盘).
由于各种原因(输入错误,网络故障,计算错误等),管道块内的lambda函数可能会抛出异常.在这种情况下,我不想破坏整个管道,而是想要触发违规项目,并在"错误"下的UI中显示它.
最好的方法是什么?我知道我可以在try/catch中包装每个lambda函数:
var errorLoggingBlock = new ActionBlock<Tuple<WorkItem, Exception>>(...)
var workerBlock = new TransformBlock<WorkItem, WorkItem>(item =>
{
try {
return DoStuff(item);
} catch (Exception ex) {
errorLoggingBlock.SendAsync(Tuple.Create(item, ex));
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
但是我在管道中有大约10个块,并且将代码复制/粘贴到每个块中似乎很愚蠢.此外,我不喜欢返回null的想法,因为现在所有下游块都必须检查它.
我的下一个最好的想法是创建一个函数,返回一个为我做包装的lambda:
private Func<TArg, TResult> HandleErrors<TArg, TResult>(Func<TArg, TResult> f) where TArg:WorkItem
{
return arg =>
{
try {
return f(arg);
} catch (Exception ex) {
errorLoggingBlock.SendAsync(Tuple.Create(item, ex));
return default(TResult);
}
};
}
Run Code Online (Sandbox Code Playgroud)
但这似乎有点过分.有没有更好的办法 ?
这是一个非常有趣的话题。
您可以在链接块时定义过滤器,这意味着您可以将错误结果转移到错误处理块。为此,块应该返回“元”对象,其中包含其处理结果和至少一个失败/成功指示器。
这个想法在面向铁路的编程中得到了更好的描述,其中链中的每个函数处理成功的结果或将失败的结果转移到“失败的轨道”以进行最终记录。
实际上,这意味着您应该在每个块之后添加两个链接:一个具有转移到错误处理块的过滤条件,另一个是转到流程中下一步的默认链接。
您甚至可以结合这两种想法来处理部分故障。部分失败结果将包含失败指示符和有效负载。您可以将结果转移到日志块,然后再将其传递到下一步。
我发现明确每条消息的状态比尝试通过检查 null、缺失值等来确定其状态要容易得多。这意味着块应该将其结果包装在包含状态标志的“信封”对象中,结果和/或任何错误。