I'm curious if a console app written in .NET Core running on Windows can intercept a SIGKILL event and basically know it's being terminated. Here's the code I'm trying:
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..");
}
}
When I run the program from the command line, I can terminate it with the CTRL+C key combination. This will fire CancelKeyPress
as well as Unloading
. 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.
This is part of a larger goal, which is to trap a Docker container shutting down. On Windows, the docker stop
command will kill the main process using SIGTERM. This behavior is configurable on Linux Docker using the --stop-signal
or STOPSIGNAL
features, but those things have not been implemented on Windows.
On Windows, the docker stop command will kill the main process using SIGTERM.
So, depending on your versions, Docker may send CTRL_CLOSE_EVENT
or CTRL_SHUTDOWN_EVENT
.
These are different than the Ctrl-C signal, which is CTRL_C_EVENT
. .NET's Console.CancelKeyPress
only handles CTRL_C_EVENT
(or the closely-related CTRL_BREAK_EVENT
), so it will not be called for CTRL_CLOSE_EVENT
or 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.
It is not possible to handle all kill signals. I believe Task Manager these days tries to do a "gentle" close which in this case is probably sending CTRL_CLOSE_EVENT
, but it is also entirely possible to just TerminateProcess
a process, which kills it immediately without any signals or anything.
But recognizing a Docker-initiated shutdown and responding to it is possible, since it sends a nice signal first and only terminates after a timeout.
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.
The only workaround I'm aware of is to install your own Console control event handler. I recommend handling CTRL_C_EVENT
, CTRL_CLOSE_EVENT
, and CTRL_SHUTDOWN_EVENT
all as just a generic "shutdown" signal.