C#TPL任务传播异常 - 多级任务



Run()方法(代码的第一个块)呼叫GetImpairedNodesFromCASpectrumAsync(),这又呼叫GetRoutersOn3GBackupNodeStatusesAsync()

当前,如果GetRoutersOn3GBackupNodeStatusesAsync()中的任何任务失败(由于例外),我在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;
}

您的问题归因于ContinueWith,该问题将在未满足条件时取消其延续(即TaskContinuationOptions.OnlyOnRanToCompletion)。

作为一般规则,使用await代替ContinueWith

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;
}

最新更新