我正在使用ASP.NET 4网站(而非Web应用程序)。我试图使用IRegisteredObject
允许一些长时间运行的代码在非请求线程中运行。
为了进行测试,我已将IIS 7.5应用程序池的循环间隔设置为较低的值,以便在后台线程运行时尝试回收。
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);
}
}
}
}
当应用程序池被回收时,调用IRegisteredObject.Stop
并将immediate
设置为false
。但是,该过程似乎在Stop
返回之前终止;永远无法联系到HostingEnvironment.UnregisterObject
。这种行为似乎与我读到的以下信息相反:
- 如果30秒后仍有运行的注册对象,ASP.NET将在其上调用
IRegisteredObject.Stop(true)
。- ASP.NET将在返回所有第二个通知后卸载AppDomain。
Performing Asynchronous Work, or Tasks, in ASP.NET Applications:
如果需要,可以根据需要暂停卸载,因为在Stop方法第二次返回之前我们不会卸载。
答案 0 :(得分:2)
实际上,IRegisteredObject按预期工作。我想你发生的事情是你的任务可能需要超过“关机时间限制”IIS AppPool设置中的默认90秒。在这种情况下,工人进程将被强行杀死。因此,不是aspnet就是杀死进程,而是IIS。修改关机时间限制应该解决问题,只要注意它不会造成任何麻烦,因为你将有更多的工作进程实例存活(但旧的只会处理Stop()方法,它赢了'处理新请求。)