我捕获的聚合异常没有我期望的异常
本文关键字:异常 没有我 期望 | 更新日期: 2023-09-27 18:29:54
我正在使用任务并行库来设置任务链,如下所示,但我得到了一个我不理解的奇怪的异常处理体验。
我使用 Parallel.ForEach 并调用一个 Action,其中包括对以下方法的调用。这个平行线被包裹在一个尝试...catch(AggregateException(并且当发生异常时 - 就像在其中一个并行分支中一样 - 一个SchemaValidation异常,那么我希望在AggregateException中看到它。
但是,我得到的是"任务被取消" - 任务取消异常。我的 SchemaValidationException 去哪儿了?
private static void ProcessChunk(Task<ISelectedChunk> selectionTask,
IRepository repository,
IIdentifiedExtractChunk identifiedExtractChunk,
IBatchRunConfiguration batchRunConfiguration,
IBatchRun batchRun,
ILog log,
IAuthenticationCertificate authenticationCertificate,
IFileSystem fileSystem,
long batchRunRid)
{
var transformationTask = selectionTask.ContinueWith(TransformationFunction.Transformation(identifiedExtractChunk, batchRunConfiguration, batchRun),
TaskContinuationOptions.NotOnFaulted);
var schemaValidationTask = transformationTask.ContinueWith(SchemaValidationFunction.SchemaValidationTask(batchRunConfiguration),
TaskContinuationOptions.NotOnFaulted);
var compressTask = schemaValidationTask.ContinueWith(CompressFunction.CompressTask(identifiedExtractChunk),
TaskContinuationOptions.NotOnFaulted);
var encryptTask = compressTask.ContinueWith(EncryptionFunction.EncryptTask(authenticationCertificate),
TaskContinuationOptions.NotOnFaulted);
var fileGenerationTask = encryptTask.ContinueWith(FileGenerationFunction.FileGenerationTask(identifiedExtractChunk, batchRunConfiguration, fileSystem),
TaskContinuationOptions.NotOnFaulted);
// Take the time before we start the processing
DateTime startBatchItemProcessing = DateTime.Now;
// Start with the Selection Task
selectionTask.Start();
// And wait on the last task in the chain
fileGenerationTask.Wait();
// Take the time at the end of the processing
DateTime endBatchItemProcessing = DateTime.Now;
// Record all the relevant information and add it to the collection
IBatchChunkProcessed batchChunkProcessed = GetBatchItemProcessed(identifiedExtractChunk, batchRunRid, fileGenerationTask.Result, transformationTask.Result.Item2, startBatchItemProcessing, endBatchItemProcessing);
BatchItemsProcessed.Add(batchChunkProcessed);
让我们稍微简化一下您的代码:
var t1 = Task.Factory.StartNew(a1);
var t2 = t1.ContinueWith(a2, TaskContinuationOptions.NotOnFaulted);
var t3 = t2.ContinueWith(a3, TaskContinuationOptions.NotOnFaulted);
t3.Wait();
现在假设a1
引发异常。发生的情况是t1
变得有故障(t1.Status == TaskStatus.Faulted
(。因此,t2
无法运行(因为NotOnFaulted
(,因此将被取消。但这不是你所期望的:t2
不会被错误,它将被取消(t2.Status == TaskStatus.Canceled
(。但这意味着t3
可以正常运行,如果不抛出,t3.Wait()
也不会抛出任何异常。
如何解决这个问题?首先,您可能不应该使用 TaskContinuationOptions.NotOnFaulted
,而是TaskContinuationOptions.OnlyOnRanToCompletion
。但这并不能解决"消失"异常的问题。为了解决这个问题,我认为有两种可能性:
在每个延续的开头调用
Wait()
,不要使用任何TaskContinuationOptions
。这意味着你可能会得到一些用AggregateException
包裹的异常,它本身被包裹在AggregateException
中,它被包裹在另一个AggregateException
中,等等。要解决此问题,您可以使用Flatten()
或Handle()
.等待所有任务,通过使用
Task.WaitAll()
.WaitAll()
将抛出一个AggregateException
,其中包含原始异常,并且还会TaskCanceledException
由于第一个异常而取消的每个任务。