.Net Core - How to Properly Kill Started Process

.net core - How to properly kill started process?

As suggested by @mjwills I've updated the process as follows:

class Program
{
static Process webAPI;

static async Task Main(string[] args)
{
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;

webAPI = new Process
{
StartInfo = new ProcessStartInfo("dotnet")
{
UseShellExecute = false,
WorkingDirectory = "C:/Project/publish",
Arguments = "WebAPI.dll",
CreateNoWindow = true
}
};
using (webAPI)
{
webAPI.Start();
webAPI.WaitForExit();
}
}

static void CurrentDomain_ProcessExit(object sender, EventArgs e)
{
webAPI.Close();
}
}

dotnet core how to shutdown child process gracefully

Technically you could simply call Process.Kill() in order to immediately shut down the process. However, a lot of the time that is not the way to go simply because the WebAPI might be in middle of important operations and you can't really tell when those actions may be happening and Process.Kill() is not really considered "graceful".

What would be most prudent to do is to tell the process that you would like for it to shut down at the earliest convenience and then allow for the WebAPI to clean things up before it exits itself. If you are desiging the WebAPI that is even better because that way you can decide on how to do this. Only calling Kill() when it is absolutely necessary.

You can do that multiple ways of course. Some that come to mind are Sockets that are periodically checked and sending a CTRL+C input to the WebAPI.


public Task StopAsync(CancellationToken cancellationToken)
{
// send request to shut down

// wait for process to exit and free its resources
process.WaitForExit();
process.Close();
process.Dispose();



_timer?.Change(Timeout.Infinite, 0);

return Task.CompletedTask;
}

Of course if this is Async then it wouldn't make sense to wait for it to exit inside of the method so you would simply wait or check if it has exited outside of this method.

Children processes created in ASP.NET Core Process gets killed on exit

As I said in my comment, there is a Job Object which is created by ASP.NET core in the out-of-process scenario. The relevant source code portion is here:

https://github.com/aspnet/AspNetCore/blob/master/src/Servers/IIS/AspNetCoreModuleV2/OutOfProcessRequestHandler/serverprocess.cpp#L89

HRESULT
SERVER_PROCESS::SetupJobObject(VOID)
{
HRESULT hr = S_OK;
JOBOBJECT_EXTENDED_LIMIT_INFORMATION jobInfo = { 0 };

if (m_hJobObject == NULL)
{
....
jobInfo.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;

if (!SetInformationJobObject(m_hJobObject,
JobObjectExtendedLimitInformation,
&jobInfo,
sizeof jobInfo))
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}

return hr;
}

As per documentation, JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE:

Causes all processes associated with the job to terminate when the
last handle to the job is closed.

If you dig the source further, it does not seem to be optional.

Now, you can actually see this by yourself, if you reproduce your steps. Use Process Explorer, and navigate to your dotnet.exe process, this is what it will display:

enter image description here

  • note 1: in fact calc.exe stays alive (at least in my Windows 10 installation because it's now a WinRT app, so it will not end up as child of dotnet.exe), that's why I used notepad.exe
  • note 2: iisexpress.exe also creates a job object, but it's configured as breakaway ok, which means it won't kill child processes.
  • note 3: if you run from Visual Studio (not my screenshot), you may see an intermediary VSIISExeLauncher.exe process between iisexpress.exe and dotnet.exe. This one also creates a Job Object with 'kill on close' to add to the confusion...

Kill process tree programmatically in C#

This worked very nicely for me:

/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
private static void KillProcessAndChildren(int pid)
{
// Cannot close 'system idle process'.
if (pid == 0)
{
return;
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection moc = searcher.Get();
foreach (ManagementObject mo in moc)
{
KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
}
try
{
Process proc = Process.GetProcessById(pid);
proc.Kill();
}
catch (ArgumentException)
{
// Process already exited.
}
}
Update 2016-04-26

Tested on Visual Studio 2015 Update 2 on Win7 x64. Still works as well now as it did 3 years ago.

Update 2017-11-14

Added check for system idle process if (pid == 0)

Update 2018-03-02

Need to add a reference to the System.Management namespace, see comment from @MinimalTech below. If you have ReSharper installed, it will offer to do this for you automatically.

Update 2018-10-10

The most common use case for this is killing any child processes that our own C# process has started.

In this case, a better solution is to use Win32 calls within C# to make any spawned process a child process. This means that when the parent process exits, any child processes are automatically closed by Windows, which eliminates the need for the code above. Please let me know if you want me to post the code.



Related Topics



Leave a reply



Submit