Task.Factory.StartNew() 在使用 ContinueWith() 时不包含异常
Task.Factory.StartNew() doesn't include Exception when using ContinueWith()
我正在尝试创建一个不会阻塞我的主线程但仍会记录错误以防出现异常的并行进程。最初我有这个代码:
var task = Task.Run(
() => _db.addData());
task.ContinueWith(continuationTask =>
{
if (continuationTask.Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
当运行将应用代码_taskScheduler
设置为TaskScheduler.Current
时。
当 运行 执行此操作时,它会正确地并行执行代码,当数据库出现问题时,continuationTask.Exception
包含相应的异常消息。
指定 TaskScheduler
的全部意义在于我可以控制单元测试中的执行顺序。就目前而言,在单元测试中,原始任务和延续任务将 运行 使用不同的任务调度程序 - 分别为 TaskScheduler
和 MockTaskScheduler
。 (为简洁起见未显示单元测试代码,但 MockTaskScheduler
只是允许我排队和执行任务的自定义实现)
由于 Task.Run
没有将 TaskScheduler
作为参数我尝试将代码更改为
var task = Task.Factory.StartNew(
() => _db.addData(),
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler);
task.ContinueWith(continuationTask =>
{
if (continuationTask .Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
这使我的测试工作非常完美,因为我现在可以控制每个任务何时执行,因为它们使用相同的可注射 _taskScheduler
。但是,当 运行 使用 TaskScheduler.Current
连接应用程序代码时,continuationTask.Exception
始终为 null,从而阻止我记录任何异常。
为什么 Task.Run
填充 continuationTask.Exception
而 Task.Factory.StartNew
没有?我错过了什么吗?
正如@Mike Zboray 在评论中提到的,我需要调用 task.Unwrap().ContinueWith()
因为我有嵌套任务。这仅在使用 Task.Factory.StartNew()
时才有必要,因为 Task.Run()
会自动展开嵌套任务。
我的最终代码如下所示:
var task = Task.Factory.StartNew(
() => _db.addData(),
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler);
task.Unwrap().ContinueWith(continuationTask =>
{
if (continuationTask .Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
我正在尝试创建一个不会阻塞我的主线程但仍会记录错误以防出现异常的并行进程。最初我有这个代码:
var task = Task.Run(
() => _db.addData());
task.ContinueWith(continuationTask =>
{
if (continuationTask.Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
当运行将应用代码_taskScheduler
设置为TaskScheduler.Current
时。
当 运行 执行此操作时,它会正确地并行执行代码,当数据库出现问题时,continuationTask.Exception
包含相应的异常消息。
指定 TaskScheduler
的全部意义在于我可以控制单元测试中的执行顺序。就目前而言,在单元测试中,原始任务和延续任务将 运行 使用不同的任务调度程序 - 分别为 TaskScheduler
和 MockTaskScheduler
。 (为简洁起见未显示单元测试代码,但 MockTaskScheduler
只是允许我排队和执行任务的自定义实现)
由于 Task.Run
没有将 TaskScheduler
作为参数我尝试将代码更改为
var task = Task.Factory.StartNew(
() => _db.addData(),
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler);
task.ContinueWith(continuationTask =>
{
if (continuationTask .Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);
这使我的测试工作非常完美,因为我现在可以控制每个任务何时执行,因为它们使用相同的可注射 _taskScheduler
。但是,当 运行 使用 TaskScheduler.Current
连接应用程序代码时,continuationTask.Exception
始终为 null,从而阻止我记录任何异常。
为什么 Task.Run
填充 continuationTask.Exception
而 Task.Factory.StartNew
没有?我错过了什么吗?
正如@Mike Zboray 在评论中提到的,我需要调用 task.Unwrap().ContinueWith()
因为我有嵌套任务。这仅在使用 Task.Factory.StartNew()
时才有必要,因为 Task.Run()
会自动展开嵌套任务。
我的最终代码如下所示:
var task = Task.Factory.StartNew(
() => _db.addData(),
CancellationToken.None,
TaskCreationOptions.None,
_taskScheduler);
task.Unwrap().ContinueWith(continuationTask =>
{
if (continuationTask .Exception != null)
{
_logger.LogError(continuationTask.Exception, "Failed to log mismatch");
}
},
_taskScheduler);