Background
I'm working on an ASP.NET 4 web site (not web application). I'm trying to use IRegisteredObject
to allow some long-running code to run in a non-request thread.
For testing, I've set the IIS 7.5 application pool's recycle interval to low values so that it will try to recycle while the background thread is running.
Code
public class AspFriendlyBackgroundJob
{
private readonly object key = new object();
private readonly Task task;
public AspFriendlyBackgroundJob(Action work)
{
lock (key)
{
HostingEnvironment.RegisterObject(new Stopper(this));
task = Task.Factory.StartNew(work);
}
}
class Stopper : IRegisteredObject
{
private readonly AspFriendlyBackgroundJob job;
public Stopper(AspFriendlyBackgroundJob job)
{
this.job = job;
}
public void Stop(bool immediate)
{
lock (job.key)
{
job.task.Wait();
HostingEnvironment.UnregisterObject(this);
}
}
}
}
Problem
When the application pool was recycled, IRegisteredObject.Stop
was called with immediate
set to false
. However, the process appears to terminate before Stop
returns; the call to HostingEnvironment.UnregisterObject
never gets reached. This behaviour seems contrary to the following information I read:
- If there are still registered objects running after 30 seconds, ASP.NET will call
IRegisteredObject.Stop(true)
on them.- ASP.NET will unload the AppDomain after all those second notifications have returned.
Performing Asynchronous Work, or Tasks, in ASP.NET Applications:
If you need to, you can hold up the unload as long as you like, because we won’t unload until your Stop method returns the second time.
Actually, IRegisteredObject works as expected. What I guess is happening to you is that your task might take more than the default 90 seconds in the "Shutdown Time Limit" IIS AppPool setting. In that case, the worker process will be forcibly killed. So it's not aspnet that's killing the process, but rather IIS. Modifying the Shutdown Time Limit should fix the problem, just take care it doesn't cause any trouble as you'll have more instances of the worker process alive (but the old one will be only processing the Stop() method, it won't handle new requests).