2012-04-04 48 views
4

我正在使用任務並行庫來設置任務鏈,如下所示,但我得到了一個奇怪的異常處理經驗,我不明白。AggregateException我發現沒有異常我期望

我使用Parallel.ForEach並調用一個包含對以下方法的調用的Action。這個Parallel.ForEach被封裝在一個try ... catch(AggregateException)中,當發生異常時 - 就像它在一個並行分支中那樣 - 一個SchemaValidation異常,那麼我期望在AggregateException中看到這種異常。

但是,我得到的是'任務被取消' - TaskCanceledException。我的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); 
+1

爲什麼你甚至在這裏使用'任務'?爲什麼不按順序執行所有的方法? – svick 2012-04-04 12:44:59

+1

該代碼似乎與該問題沒有任何關係。發佈捕獲和處理異常的代碼。 – 2012-04-04 13:15:27

+0

@svick - 傳入的選擇任務是並行的。此外,這些是離散的積木任務,可以在其他情況下輕鬆地重新使用 - 並且可能成爲根本任務。 – Ciaran 2012-04-04 15:49:39

回答

6

讓我們來簡化你的代碼位:

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。但是這並不能解決「消失」例外的問題。爲了解決這個問題,我看到兩種可能性:

  1. 呼叫Wait()在每個連續的開始,不使用任何TaskContinuationOptions。這意味着你可能會得到一些包裝在AggregateException中的異常,它本身被包裝在AggregateException中,包裝在另一個AggregateException等中。爲了解決這個問題,可以使用Flatten()Handle()

  2. 等待所有的任務,通過使用Task.WaitAll()WaitAll()將拋出一個AggregateException,它將包含原始異常,並且對於因第一個異常而被取消的每個任務也將包含TaskCanceledException

+0

我去了Task.WaitAll選項 - 看起來最乾淨。我現在得到我想要的異常以及TaskCanceledExceptions。非常感謝。 – Ciaran 2012-04-04 15:46:03