Windows 上的 .NET Core 应用程序可以捕获 SIGTERM 事件吗?
Can a .NET Core application on Windows trap a SIGTERM event?
我很好奇在 Windows 上使用 .NET Core 运行ning 编写的控制台应用程序是否可以拦截 SIGKILL 事件并且基本上知道它正在终止。这是我正在尝试的代码:
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine($"Hello from PID {Process.GetCurrentProcess().Id}, press CTRL+C to exit.");
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).Unloading += context =>
{
Console.WriteLine("SIGTERM received, exiting program...");
};
Console.CancelKeyPress += (s, e) =>
{
Console.WriteLine("SIGINT received, exiting program...");
Environment.Exit(0);
};
try
{
await Task.Delay(Timeout.Infinite);
}
finally
{
Console.WriteLine("Finally executed..");
}
}
当我从命令行 运行 程序时,我可以使用 CTRL+C 组合键终止它。这将触发 CancelKeyPress
以及 Unloading
。如果我以其他方式终止程序(使用 Windows 任务管理器 "End Process" 函数,或 Stop-Process
PowerShell 命令),该过程将直接结束,而不会向控制台写入任何输出。
这是更大目标的一部分,即捕获 Docker 容器关闭。在 Windows 上,docker stop
命令将使用 SIGTERM 终止主进程。此行为可使用 --stop-signal
或 STOPSIGNAL
功能在 Linux Docker 上配置,但这些功能尚未在 Windows.
上实现
On Windows, the docker stop command will kill the main process using SIGTERM.
因此,根据您的版本,Docker 可能会发送 CTRL_CLOSE_EVENT
或 CTRL_SHUTDOWN_EVENT
。
这些不同于 Ctrl-C 信号,后者是 CTRL_C_EVENT
。 .NET's Console.CancelKeyPress
only handles CTRL_C_EVENT
(or the closely-related CTRL_BREAK_EVENT
),因此不会为 CTRL_CLOSE_EVENT
或 CTRL_SHUTDOWN_EVENT
调用。
If I terminate the program other ways (Using the Windows Task Manager "End Process" function, or the Stop-Process PowerShell command), the process simply ends without any output written to the console.
不可能处理所有终止信号。我相信这些天任务管理器试图做一个 "gentle" 关闭,在这种情况下可能会发送 CTRL_CLOSE_EVENT
,但也完全有可能只 TerminateProcess
一个进程,它会立即杀死它而不会任何信号或任何东西。
但识别 Docker 启动的关闭并对其做出响应是可能的,因为它首先发送一个良好的信号并且仅在超时后终止。
The .NET Runtime will recognize CTRL_CLOSE_EVENT
as a process exit request, but since newer versions of Docker for Windows have switched to CTRL_SHUTDOWN_EVENT
, I believe that .NET will simply not do a graceful shutdown for Windows containers anymore.
我知道的唯一解决方法是安装您自己的控制台控件事件处理程序。我推荐handling CTRL_C_EVENT
, CTRL_CLOSE_EVENT
, and CTRL_SHUTDOWN_EVENT
all as just a generic "shutdown" signal.
我想 post .NET Core 控制台应用程序的完整工作代码,当 运行 在 Docker 容器中(使用 docker run -d
)时,可以响应 docker stop
命令。请永远使用它!
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace DockerTest
{
class Program
{
private enum ConsoleControlEvent : uint { CTRL_C_EVENT = 0, CTRL_CLOSE_EVENT = 2, CTRL_SHUTDOWN_EVENT = 6 }
private static void ConsoleCtrlHandler(ConsoleControlEvent controlType)
{
if (controlType == ConsoleControlEvent.CTRL_C_EVENT || controlType == ConsoleControlEvent.CTRL_CLOSE_EVENT ||
controlType == ConsoleControlEvent.CTRL_SHUTDOWN_EVENT)
{
Console.WriteLine("Docker container is shutting down..");
Environment.Exit(0);
}
}
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate void SetConsoleCtrlHandler_HandlerRoutine(ConsoleControlEvent controlType);
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
private static extern bool SetConsoleCtrlHandler(SetConsoleCtrlHandler_HandlerRoutine handler,
[MarshalAs(UnmanagedType.Bool)] bool add);
static void Main()
{
Console.CancelKeyPress += (_, args) => { };
if (!SetConsoleCtrlHandler(ConsoleCtrlHandler, add: true))
throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
Console.WriteLine("Waiting to be stopped.");
Thread.Sleep(-1);
}
}
}
证据如下:
主要感谢@Stephen Cleary,所以请为他的回答点赞。我不是英雄
我很好奇在 Windows 上使用 .NET Core 运行ning 编写的控制台应用程序是否可以拦截 SIGKILL 事件并且基本上知道它正在终止。这是我正在尝试的代码:
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine($"Hello from PID {Process.GetCurrentProcess().Id}, press CTRL+C to exit.");
AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).Unloading += context =>
{
Console.WriteLine("SIGTERM received, exiting program...");
};
Console.CancelKeyPress += (s, e) =>
{
Console.WriteLine("SIGINT received, exiting program...");
Environment.Exit(0);
};
try
{
await Task.Delay(Timeout.Infinite);
}
finally
{
Console.WriteLine("Finally executed..");
}
}
当我从命令行 运行 程序时,我可以使用 CTRL+C 组合键终止它。这将触发 CancelKeyPress
以及 Unloading
。如果我以其他方式终止程序(使用 Windows 任务管理器 "End Process" 函数,或 Stop-Process
PowerShell 命令),该过程将直接结束,而不会向控制台写入任何输出。
这是更大目标的一部分,即捕获 Docker 容器关闭。在 Windows 上,docker stop
命令将使用 SIGTERM 终止主进程。此行为可使用 --stop-signal
或 STOPSIGNAL
功能在 Linux Docker 上配置,但这些功能尚未在 Windows.
On Windows, the docker stop command will kill the main process using SIGTERM.
因此,根据您的版本,Docker 可能会发送 CTRL_CLOSE_EVENT
或 CTRL_SHUTDOWN_EVENT
。
这些不同于 Ctrl-C 信号,后者是 CTRL_C_EVENT
。 .NET's Console.CancelKeyPress
only handles CTRL_C_EVENT
(or the closely-related CTRL_BREAK_EVENT
),因此不会为 CTRL_CLOSE_EVENT
或 CTRL_SHUTDOWN_EVENT
调用。
If I terminate the program other ways (Using the Windows Task Manager "End Process" function, or the Stop-Process PowerShell command), the process simply ends without any output written to the console.
不可能处理所有终止信号。我相信这些天任务管理器试图做一个 "gentle" 关闭,在这种情况下可能会发送 CTRL_CLOSE_EVENT
,但也完全有可能只 TerminateProcess
一个进程,它会立即杀死它而不会任何信号或任何东西。
但识别 Docker 启动的关闭并对其做出响应是可能的,因为它首先发送一个良好的信号并且仅在超时后终止。
The .NET Runtime will recognize CTRL_CLOSE_EVENT
as a process exit request, but since newer versions of Docker for Windows have switched to CTRL_SHUTDOWN_EVENT
, I believe that .NET will simply not do a graceful shutdown for Windows containers anymore.
我知道的唯一解决方法是安装您自己的控制台控件事件处理程序。我推荐handling CTRL_C_EVENT
, CTRL_CLOSE_EVENT
, and CTRL_SHUTDOWN_EVENT
all as just a generic "shutdown" signal.
我想 post .NET Core 控制台应用程序的完整工作代码,当 运行 在 Docker 容器中(使用 docker run -d
)时,可以响应 docker stop
命令。请永远使用它!
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace DockerTest
{
class Program
{
private enum ConsoleControlEvent : uint { CTRL_C_EVENT = 0, CTRL_CLOSE_EVENT = 2, CTRL_SHUTDOWN_EVENT = 6 }
private static void ConsoleCtrlHandler(ConsoleControlEvent controlType)
{
if (controlType == ConsoleControlEvent.CTRL_C_EVENT || controlType == ConsoleControlEvent.CTRL_CLOSE_EVENT ||
controlType == ConsoleControlEvent.CTRL_SHUTDOWN_EVENT)
{
Console.WriteLine("Docker container is shutting down..");
Environment.Exit(0);
}
}
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
private delegate void SetConsoleCtrlHandler_HandlerRoutine(ConsoleControlEvent controlType);
[DllImport("kernel32.dll", SetLastError = true, CallingConvention = CallingConvention.Winapi)]
private static extern bool SetConsoleCtrlHandler(SetConsoleCtrlHandler_HandlerRoutine handler,
[MarshalAs(UnmanagedType.Bool)] bool add);
static void Main()
{
Console.CancelKeyPress += (_, args) => { };
if (!SetConsoleCtrlHandler(ConsoleCtrlHandler, add: true))
throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
Console.WriteLine("Waiting to be stopped.");
Thread.Sleep(-1);
}
}
}
证据如下:
主要感谢@Stephen Cleary,所以请为他的回答点赞。我不是英雄