为什么 .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。
如果 IHostedService
在 StartAsync
期间抛出异常,则 IHost
将无法启动。
因此,如果您的 BackgroundService
在第一个 await 之前抛出异常,异常将传播并使主机失败。如果你想阻止这种情况,你可以简单地先调用 await Task.Yield()
。
我在下面创建了一个示例 .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。
如果 IHostedService
在 StartAsync
期间抛出异常,则 IHost
将无法启动。
因此,如果您的 BackgroundService
在第一个 await 之前抛出异常,异常将传播并使主机失败。如果你想阻止这种情况,你可以简单地先调用 await Task.Yield()
。