c# - 数据流管道中的全局每 block 错误处理

标签 c# error-handling tpl-dataflow

我正在设计一个由多个 block 组成的长期运行的数据流管道。项目被馈送到管道的输入 block ,最终通过它,并在最后显示在 UI 中(出于对用户的礼貌——管道的真正工作是将处理结果保存到磁盘)。

管道 block 内的 lambda 函数可能会抛出异常,原因有多种(输入错误、网络故障、计算错误等)。在这种情况下,我不想让整个管道出错,而是想踢出有问题的项目,并将其显示在 UI 中的“错误”下。

最好的方法是什么?我知道我可以将每个 lambda 函数包装在一个 try/catch 中:

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;
    }
}

但我在管道中有大约 10 个 block ,将代码复制/粘贴到每个 block 中似乎很愚蠢。另外,我不喜欢返回 null 的想法,因为现在所有下游 block 都必须检查它。

我的下一个最佳想法是创建一个返回 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);
        }
     };
  }

但这似乎有点太元了。有没有更好的方法?

最佳答案

这是一个非常有趣的主题。

您可以在链接 block 时定义过滤器,这意味着您可以将错误结果转移到错误处理 block 。为此, block 应该返回包含其处理结果和至少一个失败/成功指示符的“元”对象。

这个想法在 Railroad Oriented Programming 中有更好的描述。 ,其中链中的每个函数处理成功的结果或将失败的结果转移到“失败的轨道”以进行最终记录。

实际上,这意味着您应该在每个 block 之后添加两个链接:一个具有转移到错误处理 block 的过滤条件,以及一个转到流程中下一步的默认链接。

您甚至可以结合这两种想法来处理部分故障。部分失败结果将包含失败指示符和有效负载。在将结果传递到下一步之前,您可以将结果转移到日志记录 block 。

我发现明确每条消息的状态比尝试通过检查空值、缺失值等来确定其状态要容易。这意味着 block 应该包装它们的结果在包含状态标志、结果和/或任何错误的“信封”对象中。

关于c# - 数据流管道中的全局每 block 错误处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31956521/

相关文章:

c# - 如何在 mysql 中使用触发器将列的值从特定日期更新到仅针对唯一客户 ID 的日期

c# - 在 TPL 数据流中使用 async/await 和 yield return

error-handling - TCL中的错误处理

c# - TPL 数据流 block 在 UI 线程上运行

c# - TPL 数据流 : Bounded capacity and waiting for completion

c# - 向实体添加新的构造函数

c# - C# 可执行文件的 Ngen 输出不是有效的 Win32 应用程序

c# - 查询 Entity Framework 中的第 n 行

python - win32com 未从 python 文件导入 - DLL 加载失败

javascript - 如何汇总 JavaScript 错误?