2017-03-01 26 views
0

Run()方法(第一个代码块)拨打GetImpairedNodesFromCASpectrumAsync(),然后调用GetRoutersOn3GBackupNodeStatusesAsync()C#TPL任务传播异常 - 多级任务

当前,如果GetRoutersOn3GBackupNodeStatusesAsync()中的任何任务失败(由于例外),我在Run()方法中得到非常通用的异常,表示任务已取消。

如何确保我的调用堆栈中的任何任务最终将原始异常返回到run方法,以便我可以在那里处理它?

public override void Run(ref DevOpsScheduleEntryEventCollection events) 
{ 
    // I want to be able to catch any exceptions thrown from tasks in GetRoutersOn3GBackupNodeStatusesAsync() 

    Task<NetworkDeviceNodeStatus[]> CasImapairedNodesTask = 
       CasOperations.GetImpairedNodesFromCASpectrumAsync(); 
    Task.WaitAll(CasImapairedNodesTask); 
    NetworkDeviceNodeStatus[] CasImpairedNodes = CasImapairedNodesTask.Result.ToArray(); 
} 

internal virtual async Task<NetworkDeviceNodeStatus[]> GetImpairedNodesFromCASpectrumAsync() 
{ 
#if DEBUG 
    Debug.WriteLine("Entering GetNodesInCriticalCondition()"); 
    Stopwatch sw = new Stopwatch(); 
    sw.Start(); 
#endif 

    // Execute both tasks. Throw an Exception if any errors. 
    try { 
     var nodesWithCircuitsDown = new List<NetworkDeviceNodeStatus>(); 

     Task<NetworkDeviceNodeStatus[]> getAlarmingRoutersStatusesTask = null; 
     Task<NetworkDeviceNodeStatus[]> getActive3GRoutersStatusesTask = null; 

     getAlarmingRoutersStatusesTask = GetAlarmingRouterNodeStatusesAsync(); 
     getActive3GRoutersStatusesTask = GetRoutersOn3GBackupNodeStatusesAsync(); 

     await getAlarmingRoutersStatusesTask; 
     await getActive3GRoutersStatusesTask; 

     var threeGNodeStatuses = new List<NetworkDeviceNodeStatus>(); 
     var offlineNodeStatuses = new List<NetworkDeviceNodeStatus>(); 


     // Check if any nodes were hard down, but quickly came up on 3G 
     foreach (var status in getAlarmingRoutersStatusesTask.Result) { 
      var threeGStatus = getActive3GRoutersStatusesTask.Result. 
       FirstOrDefault(x => x.DeviceRetrievalId == status.DeviceRetrievalId); 

      if (threeGStatus == null) { 
       offlineNodeStatuses.Add(status); 
      } 
     } 

     foreach (var status in getActive3GRoutersStatusesTask.Result) { 
      threeGNodeStatuses.Add(status); 
     } 

     nodesWithCircuitsDown.AddRange(threeGNodeStatuses); 
     nodesWithCircuitsDown.AddRange(offlineNodeStatuses); 

     Trace.TraceInformation("{0} nodes with main data circuit down.", nodesWithCircuitsDown.Count); 
#if DEBUG 
     sw.Stop(); 
     Debug.WriteLine("Leaving GetNodesInCriticalCondition(). [" + sw.Elapsed.TotalSeconds + "]"); 
#endif 
     return nodesWithCircuitsDown.ToArray(); 
    } catch (AggregateException ae) { 
     StringBuilder sb = new StringBuilder(); 
     foreach (var e in ae.Flatten().InnerExceptions) { 
      sb.Append(e.Message + "\n"); 
     } 
     throw new Exception("One of more errors occured while retrieving impaired nodes.\n" + sb.ToString()); 
    } 
} 

virtual internal async Task<NetworkDeviceNodeStatus[]> GetRoutersOn3GBackupNodeStatusesAsync() 
{ 
    List<Branch3GInfo> branchActive3GInfos = new List<Branch3GInfo>(); 

    var nodeStatuses = new List<NetworkDeviceNodeStatus>(); 
    Task<Branch3GInfo[]> getActive3GRoutersTask = GetNodesOn3GBackupAsyncInternal(); 
    NetworkDeviceNodeStatus[] deviceStatuses = new NetworkDeviceNodeStatus[0]; 

    Task getBasicInfoTasks = await getActive3GRoutersTask.ContinueWith(async x => 
    { 
     branchActive3GInfos = x.Result.Where(y => y.Status == Branch3GInfo.Branch3GStatus.Active).ToList(); 
     Trace.TraceInformation("Found " + x.Result.Count() + " CAS Nodes on 3G backup."); 

     foreach (var branchActive3GInfo in branchActive3GInfos) { 
      await branchActive3GInfo.RouterInfo.GetBasicInfoAsync(); 
      Trace.TraceInformation("Retrieved ModelBasicInfo for " 
       + branchActive3GInfo.RouterInfo.GetBasicInfo()); 
     } 

    }, TaskContinuationOptions.OnlyOnRanToCompletion); 

    await getBasicInfoTasks.ContinueWith(x => 
    { 
     deviceStatuses = GetNetworkDeviceNodeStatuses(branchActive3GInfos.ToArray()); 
     return deviceStatuses; 
    }, TaskContinuationOptions.OnlyOnRanToCompletion); 

    return deviceStatuses; 
} 
+0

时CasImapairedNodesTask只有一个任务:

一般来说,使用await代替ContinueWith? –

+0

[异步异常处理](https://msdn.microsoft.com/en-us/library/dd997415(v = vs.110).aspx),您是否确定没有看到“AggregateException”? – JSteward

+0

@BrandonKramer旧代码,它曾经是多个任务。 – blgrnboy

回答

2

你的问题是由于ContinueWith,这将取消其延续当条件不满足(即,TaskContinuationOptions.OnlyOnRanToCompletion)。你为什么要使用Task.WaitAll(CasImapairedNodesTask)

virtual internal async Task<NetworkDeviceNodeStatus[]> GetRoutersOn3GBackupNodeStatusesAsync() 
{ 
    List<Branch3GInfo> branchActive3GInfos = new List<Branch3GInfo>(); 

    var nodeStatuses = new List<NetworkDeviceNodeStatus>(); 
    NetworkDeviceNodeStatus[] deviceStatuses = new NetworkDeviceNodeStatus[0]; 
    var result = GetNodesAsync(); 
    deviceStatuses = GetNetworkDeviceNodeStatuses(branchActive3GInfos.ToArray()); 
    return deviceStatuses; 
} 

private async Task<Branch3GInfo[]> GetNodesAsync() 
{ 
    var result = await GetNodesOn3GBackupAsyncInternal(); 
    branchActive3GInfos = result.Where(y => y.Status == Branch3GInfo.Branch3GStatus.Active).ToList(); 
    Trace.TraceInformation("Found " + x.Result.Count() + " CAS Nodes on 3G backup."); 

    foreach (var branchActive3GInfo in branchActive3GInfos) { 
    await branchActive3GInfo.RouterInfo.GetBasicInfoAsync(); 
    Trace.TraceInformation("Retrieved ModelBasicInfo for " 
      + branchActive3GInfo.RouterInfo.GetBasicInfo()); 
    } 
    return result; 
}