I have an .NET MVC site which spins up child processes for doing background work. I'd like to ensure that those processes are shut down when IIS spins up a new app domain (e. g. on deployment or any change to Web.config).
For this purpose, I've created a CriticalFinalizerObject as follows:
public class ProcessHandle : CriticalFinalizerObject, IDisposable
{
private readonly int _processId;
private int _disposed;
public ProcessHandle(int processId)
{
this._processId = processId;
}
// dispose is called if we shut down the process normally, so
// we don't need to kill it here
public void Dispose()
{
if (Interlocked.Exchange(ref this._disposed, 1) == 0)
{
GC.SuppressFinalize(this);
}
}
~ProcessHandle()
{
if (Interlocked.Exchange(ref this._disposed, 1) == 0)
{
try
{
using (var process = Process.GetProcessById(this._processId))
{
process.Kill();
}
}
catch
{
}
}
}
}
Whenever I create a process, I store a ProcessHandle alongside. The hope is that when a new app domain spins up, IIS will unload the old app domain (after some timeout). This will run the finalizers for my handles, which will kill any processes.
However, I'm observing that changing Web.config does not seem to reliably cause the finalizers to run. What am I doing wrong? Is there another way to achieve this?
Note: I'd love to have the child process watch for the parent process, but I don't control the child process code. I could create a wrapper process for this purpose, but I was hoping not to need that extra layer of complexity.