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

时间:2017-03-01 19:12:29

标签: c# task-parallel-library

Run()方法(第一个代码块)调用GetImpairedNodesFromCASpectrumAsync(),然后调用GetRoutersOn3GBackupNodeStatusesAsync()

目前,如果GetRoutersOn3GBackupNodeStatusesAsync()中的任何任务失败(由于异常),我会在Run()方法中获得一个非常通用的异常,表示该任务已被取消。

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

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

1 个答案:

答案 0 :(得分:2)

您的问题是由seq 6 | parallel -j3 ./j'{}' 引起的,当条件不满足时会取消它的继续(即ContinueWith)。

作为一般规则,请使用TaskContinuationOptions.OnlyOnRanToCompletion代替await

ContinueWith