为什么 .NET Core Worker Service 在 ExecuteAsync 方法中有两种不同的异常行为?

Why does .NET Core Worker Service has two different exception behaviors in ExecuteAsync method?

我在下面创建了一个示例 .NET Core worker 服务,它只是抛出了一个异常。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace DemoWorkerService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                throw new Exception("My Exception");

                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);
            }
        }
    }
}

上面的worker服务进程会因为预期的异常抛出而中止。

然后我将异常放在 await 语句之后,如下所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace DemoWorkerService
{
    public class Worker : BackgroundService
    {
        private readonly ILogger<Worker> _logger;

        public Worker(ILogger<Worker> logger)
        {
            _logger = logger;
        }

        protected override async Task ExecuteAsync(CancellationToken stoppingToken)
        {
            while (!stoppingToken.IsCancellationRequested)
            {
                _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                await Task.Delay(1000, stoppingToken);

                throw new Exception("My Exception");
            }
        }
    }
}

这次抛出异常后worker服务进程还在继续,我什至可以在控制台按"Ctrl+C"停止进程,这里是日志信息:

info: DemoWorkerService.Worker[0]
      Worker running at: 01/16/2020 12:26:07 +08:00
info: Microsoft.Hosting.Lifetime[0]
      Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
      Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
      Content root path: C:\MyProjects\DemoWorkerService\DemoWorkerService
info: Microsoft.Hosting.Lifetime[0]
      Application is shutting down...

这次好像是worker服务自己捕获了异常,所以没有异常 传播到外部进程,我不知道为什么工作服务会有不同的行为,我把异常放在等待之前和之后? worker service有这样两种不同的异常行为有什么原因吗?

这是设计使然。当您的服务具有 begun execution 时,BackgroundService 实现 IHostedService,并且仅实现 StartAsync 中的 returns。

如果 IHostedServiceStartAsync 期间抛出异常,则 IHost 将无法启动。

因此,如果您的 BackgroundService 在第一个 await 之前抛出异常,异常将传播并使主机失败。如果你想阻止这种情况,你可以简单地先调用 await Task.Yield()