While developing dotnet-evergreen,
I needed to figure out a way to cleanly terminate a process in a cross-platform
way without resorting to a (somewhat violent)
In Ubuntu/macOS this was trivial and worked nicely by just running
kill -s SIGINT [ProcessId]
as a new process, as documented on termination signals.
On Windows, this was far trickier. I read on Ctrl+C an Ctrl+Break signals,
looked at how ASP.NET Core hosting
handles its application lifetime,
found (shocking!) an answer on StackOverflow,
and determined that approach I needed was
AttachConsole -> GenerateConsoleCtrlEvent then wait for Process.HasExited.
Since this is somewhat involved and I wanted to make it cross-platform and easily reusable, I created the dotnet-stop tool which I can now depend on and invoke from any other dotnet tool. The whole tool fits nicely in a single C# 9 top-level Program.cs.
On Windows, invoking a separate tool for this was unavoidable (as far as I could manage), since I couldn’t re-acquire the console after signaling the external process, which left the calling tool in a broken state (wouldn’t even respond to Ctrl+C at that point). But this was perfectly acceptable for my dotnet-evergreen scenario anyway.
Usage is trivial, with a couple options to tweak how the stopping is done:
dotnet-stop Sends the SIGINT (Ctrl+C) signal to a process to gracefully stop it. Usage: dotnet stop [options] <id> Arguments: <id> ID of the process to stop. Options: -t, --timeout <timeout> Optional timeout in milliseconds to wait for the process to exit. -q, --quiet Do not display any output. [default: False] --version Show version information -?, -h, --help Show help and usage information