IHostedService 的优雅关闭
Graceful shutdown of IHostedService
我正在尝试在 .NET Core 中开发一个简单的 API,它允许异步处理请求。
- 请求已发送至控制器
- 在后台服务 (IHostedService) 上安排的工作
- 控制器returns202
- 后台服务执行长 运行 操作
由于应用程序将 运行 在 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 关闭会产生预期的行为。
我重新审视了这个问题,找到了解决方案。
IIS中的ASP.NET核心模块似乎有单独的关机时间限制,可以在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
理想情况下,这应该可以通过代码获得,这仍然是我正在努力解决的问题。如果你找到了方法,请在评论中分享。
在Configure(IApplicationBuilder app, IHostEnvironment env)函数中
注册到 IHostApplicationLifetime 中的 ApplicationStopping(当应用程序主机执行正常关闭时触发。关闭将阻塞,直到此事件完成)
var applicationLifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(OnShutdown);
私有无效 OnShutdown()
{
在关机前在这里写你想要的代码,你可以延迟关机 Thread.Sleep();
}
我正在尝试在 .NET Core 中开发一个简单的 API,它允许异步处理请求。
- 请求已发送至控制器
- 在后台服务 (IHostedService) 上安排的工作
- 控制器returns202
- 后台服务执行长 运行 操作
由于应用程序将 运行 在 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 关闭会产生预期的行为。
我重新审视了这个问题,找到了解决方案。
IIS中的ASP.NET核心模块似乎有单独的关机时间限制,可以在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
理想情况下,这应该可以通过代码获得,这仍然是我正在努力解决的问题。如果你找到了方法,请在评论中分享。
在Configure(IApplicationBuilder app, IHostEnvironment env)函数中 注册到 IHostApplicationLifetime 中的 ApplicationStopping(当应用程序主机执行正常关闭时触发。关闭将阻塞,直到此事件完成)
var applicationLifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>();
applicationLifetime.ApplicationStopping.Register(OnShutdown);
私有无效 OnShutdown() { 在关机前在这里写你想要的代码,你可以延迟关机 Thread.Sleep(); }