1

我们正在实现一个 .NET core 3.1 worker 服务,我们需要注册几个托管服务来实现所需的业务。

本文档说明IHostedService接口的StopAsync方法应该能够侦听默认 5 秒超时后发出的取消请求。

据我了解,StopAsync方法是在主机自身关机过程中被主机调用的。

在我们的一个托管服务中,我们需要在托管服务停止过程中调用异步方法;不幸的是,这个方法不支持取消,所以我们没有一个简单的方法来以正确的方式实现StopAsync方法。

这是我们的场景:

public sealed class MyHostedService : IHostedService 
{
     public async Task StopAsync(CancellationToken token)
     {
          _logger.LogInformation("Stopping the service....");

           await DoSomethingAsync(); // this method does not support cancellation, so I can't pass the cancellation token here

          _logger.LogInformation("Service was stopped");
     }
}

在这种情况下,主机级别会发生什么?

这种实现在任何方面都是“危险的”吗?

如果需要很长时间才能完成执行,这是否会阻止主机关闭过程StopAsync

这个问题最简单的解决方案是通过从BackgroundServiceMyHostedService基类 派生来实现 该类,但我想完全理解在主机级别长时间运行实现的可能含义。StopAsync

4

2 回答 2

2

托管服务按照它们启动的相反顺序停止(这也是您将它们添加到的顺序ServiceCollection)。HostOptions.ShutdownTimeout您可以通过指定默认为 5 秒来延长关闭超时:

services.Configure<HostOptions>(s => s.ShutdownTimeout = TimeSpan.FromMinutes(5));

Host停止其托管服务时,它会循环执行,以相反的顺序运行服务。一旦StopAsync为特定服务调用,主机将等待StopAsync返回。因此,如果该服务不考虑取消,则主机将需要一段时间才能关闭。

主机还在调用每个服务ThrowIfCancellationRequested()之前调用该循环。StopAsync这意味着如果在第一个服务停止时超时过去,它将完成完成*但在调用下一个服务之前StopAsync将引发异常。这将导致关闭进程中止,并且进程不正常地退出。

如果在下一个瞬间超时(ThrowIfCancellationRequested在循环之后立即有另一个),则在所有服务停止后也可能发生此中止。任何绑定到主机/应用程序生命周期的东西都将被跳过。

故事的寓意是要么确保您的服务可以快速停止,不要求您的服务需要优雅终止,或者增加超时。您还可以确保将服务添加到集合中,以便首先停止更重要或更快的服务(通过最后添加它们)并且最后停止长时间运行的服务(通过首先添加它)。

* 假设服务不考虑取消

于 2020-07-07T21:54:51.530 回答
0

基于通用网络主机关闭超时文档,主机将不优雅地停止相应的服务:

如果超时期限在所有托管服务停止之前到期,则任何剩余的活动服务都会在应用程序关闭时停止。即使服务没有完成处理,服务也会停止。如果服务需要额外的时间来停止,请增加超时时间。

长时间运行StopAsync不应阻止主机继续关机。唯一可能发生的坏事是DoSomethingAsync,如果可能的话,您将在某种无效状态下被打断。

于 2020-07-07T20:50:58.437 回答