【发布时间】:2018-11-20 14:06:28
【问题描述】:
我正在使用 TPL 数据流块来处理消息流。我的数据流网络由两个块组成,一个BufferBlock和一个ActionBlock,动作块定义为:
_actionBlock = new ActionBlock<Func<Task>>((Action<Func<Task>>) ProcessRequest,
new ExecutionDataflowBlockOptions()
{
MaxDegreeOfParallelism = 4,
});
如果动作块内部发生错误,我想让错误向上传播并退出应用程序。稍后我计划在此处添加逻辑以处理瞬态错误,但目前,任何错误都应导致应用程序退出并显示故障详细信息。为此,我添加了这样的 ContinueWith 部分:
_actionBlock
.Completion
.ContinueWith(dbt =>
{
var inner = dbt.Exception.InnerExceptions.First();
throw inner;
},
TaskContinuationOptions.OnlyOnFaulted
);
问题是“抛出内部”不会传播到任何地方,应用程序只是继续进行,就好像异常被吞噬了一样。我的代码中没有任何其他异常处理程序。作为一个实验,我已经尝试过
-
使用
重新抛出异常Dispatcher.CurrentDispatcher.Invoke(() => throw ...) 检查 ContinueWith 内容是否在 UI 线程上运行。
-
使用以下方法处理任何顶级异常:
currentDomain.UnhandledException += new UnhandledExceptionEventHandler(ToplevelHandler);
(抛出的异常永远不会到达TopLevelHandler)
这些都没有帮助。
如何使我在 ContinueWith 函数中抛出的异常传播到应用程序的顶部并让应用程序退出并显示错误消息?
【问题讨论】:
-
当你
throw inner时,你需要awaitTask在某个时候传播异常。 -
_actionBlock 运行时间很长。我在应用程序启动时创建它,并且在正常情况下它会在应用程序的整个过程中持续运行。代码中没有一个自然点可以让我在不阻塞所有内容的情况下等待它的完成任务。
-
不幸的是,这就是异常结束的地方。但在那种情况下,
ActionBlock出现故障,无论如何都不会继续处理。您可以在流程中处理异常,也可以将它们附加到流程的结果中以便在外部处理。 -
@James ActionBlocks 总是长期运行。如果你想在块完成后处理异常,不管是错误完成还是正常完成,你
await它。ContinueWith只会在 ActionBlock 完成 时运行。 -
@James 至于没有传播的异常,你写的相当于
TaskFactory.StartNew(()=>throw new Exception());。如果您不等待该任务,则异常将消失。您希望该错误出现在哪里?
标签: c# task-parallel-library tpl-dataflow