IHostedService 会在 SIGTERM 时正常停止吗?

lez*_*lon 5 c# asp.net-core

我正在尝试获取有关 asp net core 如何处理停止 IHostedService 的信息。

在我的机器上,如果我有一个使用 IHostedService 执行的应用程序,并且如果我向它发送 SIGTERM,我会观察到 StopAsync() 方法按预期调用,并且取消标记发生更改等,因此我的代码可以正常处理 SIGTERM。但是,如果我尝试在另一个环境中,似乎在 SIGTERM 上 IHostedService 被残酷地停止,而没有调用 StopAsync() 代码。所以我有一种感觉这取决于版本和潜在的环境(macos vs linux)

是否有关于 Asp .net core 将考虑“优雅”关闭需求的行为记录,具体取决于 asp .net core 版本等?我什么也没找到。理想情况下,应该记录发送 SIGTERM 时 IHostedService 的行为

Pan*_*vos 5

简洁版本

\n

使用RunConsoleAsync()而不是RunRunAsync

\n

另一种选择是在调用其他方法之一之前调用UseConsoleLifetime() 。RunConsoleAsync()在内部执行此操作

\n

Environment.Exit()从 .NET 6 开始,从应用程序本身调用时不会使用正常关闭。

\n

解释

\n

StopAsync当主机关闭时将被调用。通常,除非主机以控制台生命周期运行,否则不会监视 SIGTERM 或 SIGKILL。这是 .NET Core 3 中添加的通用主机的一项功能,并取代了旧的 WebHost。更新了 ASP.NET Core 文档,并在通用 .NET 部分中添加了新文档

\n

不幸的是,这意味着主机和中间件的行为是重复的,甚至分布在不同的部分。

\n

主机关闭部分描述了关闭行为,特别是关于 SIGTERM、MacOS、Linux 等。如果ConsoleLifetime使用,则监视 SIGTERM、SIGKILL 等。该部分并未说明如何执行此操作。

\n

这记录在.NET Generic Host for ASP.NET Core页面的RunConsoleAsync部分中:

\n
\n

RunConsoleAsync 启用控制台支持、构建并启动主机,并等待 Ctrl+C/SIGINT (Windows)、\xe2\x8c\x98+C (macOS) 或 SIGTERM 关闭。

\n
\n

当使用控制台生命周期时,SIGINT、SIGTERM、SIGKILL 将导致正常关闭:

\n
\n

如果使用 ConsoleLifetime,它会侦听以下信号并尝试正常停止主机。

\n
    \n
  • SIGINT(或 CTRL+C)。
  • \n
  • SIGQUIT(或 Windows 上的 CTRL+BREAK,Unix 上的 CTRL+\\)。
  • \n
  • SIGTERM(由其他应用程序发送,例如 docker stop)。
  • \n
\n
\n

Environment.Exit虽然不是正常关闭。这在 .NET 6 之前引起了问题:

\n
\n

在 .NET 6 之前,.NET 代码无法优雅地处理 SIGTERM。为了解决此限制,ConsoleLifetime 将订阅 System.AppDomain.ProcessExit。当 ProcessExit 被引发时,ConsoleLifetime 将通知主机停止并阻塞 ProcessExit 线程,等待主机停止。

\n
\n
\n

这导致了其他问题,因为 SIGTERM 不是引发 ProcessExit 的唯一方式。它也由应用程序中调用Environment.Exit 的代码引发。Environment.Exit 不是关闭 Microsoft.Extensions.Hosting 应用模型中进程的一种优雅方式。

\n
\n

这在 .NET 6 中发生了变化:

\n
\n

在 .NET 6 中,支持并处理 POSIX 信号。这允许 ConsoleLifetime 优雅地处理 SIGTERM,并且在调用 Environment.Exit 时不再参与其中。

\n
\n

\n
\n

对于.NET 6+,ConsoleLifetime 不再具有处理Environment.Exit 场景的逻辑。调用Environment.Exit并需要执行清理逻辑的应用程序可以自行订阅ProcessExit。在这种情况下,托管将不再尝试正常停止主机。

\n
\n