C# 异步等待在 Task.WaitAll 上抛出 AggregateException

问题描述 投票:0回答:1

我有一个基于 .NET 8 Worker Service 中的 cron 表达式的 Quartz.NET 重复作业。该作业应该调用 2 个外部 API,然后对下游的 API 响应执行一些处理。

为了提高吞吐量,我使用

Task Parallel Library
调用了 API。因此,我必须等待这两个任务完成才能开始处理。实现看起来有点像这样:

private void GetCarStatusAndPositionalInformation(
    IJobExecutionContext context, 
    string terminalNumber)
{
    CarInfo? carInfo = null; CarStatusInfo? carStatusInfo = null; 
    try
    {
        var getCarInformation = Task.Run(async () =>
        {
            var carInfoResponse = await _apiClient.QueryCarInformation(
                terminalNumber, context.CancellationToken);

            if (carInfoResponse?.CarInfo != null)
            {
                carInfo = carInfoResponse.CarInfo;
            }
            await Task.CompletedTask;
        },
        context.CancellationToken)
        .ContinueWith(
            continuationAction =>
            {
                _logger.LogWarning("Failed to get car info for terminal number: {terminalNumber}", terminalNumber);
            },
            context.CancellationToken,
            TaskContinuationOptions.OnlyOnFaulted,
            TaskScheduler.Current);

        var getCarStatusInformation = Task.Run(async () =>
        {
            var carStatusInfoResponse = await _apiClient.GetCarStatusInfoAsync(
                terminalNumber, context.CancellationToken);

            if (carStatusInfoResponse?.CarStatusInfo != null)
            {
                carStatusInfo = carStatusInfoResponse.CarStatusInfo;
            }
            await Task.CompletedTask;
        },
        context.CancellationToken)
        .ContinueWith(
            continuationAction =>
            {
                _logger.LogWarning("Failed to get car info for terminal number: {terminalNumber}", terminalNumber);
            },
            context.CancellationToken,
            TaskContinuationOptions.OnlyOnFaulted,
            TaskScheduler.Current);

        

        Task.WaitAll(
            [getCarInformation, getCarStatusInformation], timeout: TimeSpan.FromSeconds(30));

        if (carInfo != null) && carStatusInfo != null) 
        { 
            // Do some processing
        }
    }
    catch (AggregateException aex)
    {

    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Failed to obtain car status & positional information for: {terminalNumber}", terminalNumber);
    }
}

为什么我总是收到

AggregateException
的 InnerException 消息,说任务已被取消?

c# async-await quartz.net
1个回答
0
投票

问题在于您构建任务的方式。

getCarInformation
getCarStatusInformation
实际上引用了 延续,而不是您期望的任务。

现在,“快速而肮脏”的解决方案是采取两个步骤:

var getCarInformation = Task.Run(async () =>
        {
            var carInfoResponse = await _apiClient.QueryCarInformation(
                terminalNumber, context.CancellationToken);

            if (carInfoResponse?.CarInfo != null)
            {
                carInfo = carInfoResponse.CarInfo;
            }
            await Task.CompletedTask; // <- this makes no sense, btw
        },
        context.CancellationToken);
// ^^ Now you are referencing the Task you expected to reference
getCarInformation 
        .ContinueWith(
            continuationAction =>
            {
                _logger.LogWarning("Failed to get car info for terminal number: {terminalNumber}", terminalNumber);
            },
            context.CancellationToken,
            TaskContinuationOptions.OnlyOnFaulted,
            TaskScheduler.Current);

但是更清洁就是根本不使用ContinueWith

。只需将失败日志移至任务本身即可。

© www.soinside.com 2019 - 2024. All rights reserved.