【问题标题】:Graceful shutdown of IHostedService优雅关闭 IHostedService
【发布时间】:2018-08-01 13:31:05
【问题描述】:

我正在尝试在 .NET Core 中开发一个允许异步处理请求的简单 API。

  1. 请求发送到控制器
  2. 在后台服务 (IHostedService) 上安排的工作
  3. 控制器返回 202
  4. 后台服务执行长时间运行的操作

由于应用程序将在 IIS 上运行,因此在控制器返回响应后可能会发生池回收。我想实现一种允许应用程序正常关闭的方法 - 完成它当前正在执行的任务,但不接受任何新任务。

我在正常关机运行结束时遇到了困难。 出于测试目的,我简化了 StopAsync() 方法,所以现在它只包含 20 秒的异步等待:

public async Task StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("Hosted service is stopping...");

        try
        {
            // Signal cancellation to the executing method
            _stoppingTokenSource.Cancel();

            _logger.LogInformation("Delay by 20s");
            await Task.Delay(20000, cancellationToken);
            _logger.LogInformation("Delay over");
        }
        finally
        {
            // Await all pending download requests
            await Task.WhenAny(Task.WhenAll(_pendingTasks), Task.Delay(Timeout.Infinite, cancellationToken));

            _logger.LogInformation("Hosted service has been stopped successfully.");
        }
    }

日志只显示显示:

  • 托管服务正在停止...
  • 延迟 20 秒

查看 EventViewer 我可以看到 2 个为关闭而引发的事件,它们之间正好相隔 10 秒:

  • 向进程“11104”发送关闭 HTTP 消息并收到 http 状态“202”。
  • 未能正常关闭进程“11104”。

我已经试过了:

Program.cs上设置关机超时

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>()
            .UseShutdownTimeout(TimeSpan.FromMinutes(1));

检查应用程序池的高级设置:

如果你做过类似的事情,如果我做错了什么,请告诉我/指出正确的方向吗?

谢谢!

编辑

在调试应用程序时,使用 CTRL + C 关闭会产生预期的行为。

【问题讨论】:

  • 你找到这个问题的答案了吗?
  • @pcdev,我找到了一个解决方案,尽管它需要更改 Web 配置文件。我已将其发布为答案。

标签: c# iis asp.net-core iis-7.5


【解决方案1】:

再次查看问题后,我找到了解决方案。

好像IIS中的ASP.NET Core Module有单独的关闭时间限制,可以在web.config文件中配置为:

    <configuration>
      <system.webServer>
        <handlers>
          <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
        </handlers>
        <aspNetCore
            shutdownTimeLimit="30"    - set timeout here in seconds
            processPath="dotnet"
            arguments=".\GracefulShutdown.dll"
            stdoutLogEnabled="false"
            stdoutLogFile=".\logs\stdout" />
      </system.webServer>
    </configuration>

参考设置: https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/aspnet-core-module?view=aspnetcore-2.1

理想情况下,这应该可以通过代码获得,这仍然是我正在尝试解决的问题。如果您找到了方法,请在评论中分享。

【讨论】:

  • 这是非常有用的信息,谢谢!我们正在尝试做与您概述的完全相同的事情,所以这个答案会派上用场。
  • 很高兴听到。我认为您仍然应该在启动时保留 UseShutdownTimeout ,因为这将是在期限结束后触发 StopAsync 方法中令牌取消的那个。可能值得将其设置为比 ASP.NET Core 模块的实际超时时间短一点,以避免竞争条件。
  • 不错!有没有办法将此选项移至appsettings.json
  • @AsValeO 据我所知。我认为 ASP.NET Core 模块是在启动您的应用程序之前启动的,所以我认为 appsettings.json 不会改变内容。如果您找到方法,请随时更新!
【解决方案2】:

在 Configure(IApplicationBuilder app, IHostEnvironment env) 函数中 在 IHostApplicationLifetime 中注册到 ApplicationStopping(当应用程序主机执行正常关闭时触发。关闭将阻塞,直到此事件完成)

  var applicationLifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
  applicationLifetime.ApplicationStopping.Register(OnShutdown);

私人无效 OnShutdown() { 在关机前写下你想要的代码,你可以通过 Thread.Sleep(); 延迟关机 }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-26
    • 2014-02-05
    • 2019-05-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多