IRegisteredObject未按预期工作

时间:2014-11-17 03:16:35

标签: asp.net iis iis-7.5 asp.net-4.0 appdomain

背景

我正在使用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。这种行为似乎与我读到的以下信息相反:

Fire and Forget on ASP.NET

  
      
  • 如果30秒后仍有运行的注册对象,ASP.NET将在其上调用IRegisteredObject.Stop(true)
  •   
  • ASP.NET将在返回所有第二个通知后卸载AppDomain。
  •   

Performing Asynchronous Work, or Tasks, in ASP.NET Applications

  

如果需要,可以根据需要暂停卸载,因为在Stop方法第二次返回之前我们不会卸载。

1 个答案:

答案 0 :(得分:2)

实际上,IRegisteredObject按预期工作。我想你发生的事情是你的任务可能需要超过“关机时间限制”IIS AppPool设置中的默认90秒。在这种情况下,工人进程将被强行杀死。因此,不是aspnet就是杀死进程,而是IIS。修改关机时间限制应该解决问题,只要注意它不会造成任何麻烦,因为你将有更多的工作进程实例存活(但旧的只会处理Stop()方法,它赢了'处理新请求。)