在IIS7中以编程方式回收应用程序池的问题

Dar*_*ryl 2 c# iis-7

我创建了一个C#应用程序,使用Microsoft.Web.Administration.ApplicationPool类一次一个地回收IIS中的所有应用程序池.ApplicationPool上没有方法可以重新启动应用程序池(如果我错了,请纠正我),所以我认为你只需要停止,然后开始.这在大多数情况下工作正常,直到我们开始在应用程序池中获得一些陷入无限循环的线程.

默认情况下,IIS有一个90秒的"关闭时间限制",在它终止任何仍在运行的线程之前等待90秒,所以我调用ApplicationPool.Stop(),它需要90秒直到IIS终止应用程序池,在它的状态将被停止之前我可以告诉它重新开始.任何试图使用该应用程序池命中任何应用程序的内容,在我可以再次启动池之前,会在90秒内收到503错误响应.

我决定尝试以编程方式将"关闭时间限制"更改为5秒,以减少将导致503错误的应用程序数量,但IIS在终止应用程序池之前仍等待90秒.下面是我关闭应用程序池的功能:

private void StopAppPool(ApplicationPool applicationPool)
{
    ObjectState state = applicationPool.State;
    TimeSpan previousShutdownTimeLimit = applicationPool.ProcessModel.ShutdownTimeLimit;
    applicationPool.ProcessModel.ShutdownTimeLimit = new TimeSpan(0, 0, 5);
    switch (state)
    {
        case ObjectState.Started:
            applicationPool.Stop();
            WL("Application Pool {0}'s state has gone from {1} to {2}", applicationPool.Name, state, applicationPool.State);
            break;
        case ObjectState.Starting:
        case ObjectState.Unknown:
            for (int i = 0; i < 180; i++)
            {
                WL("Application Pool {0}'s state is {1}.  Waiting for state to become Started", applicationPool.Name, state);
                Thread.Sleep(500);
                state = applicationPool.State;
                if (applicationPool.State == ObjectState.Started) { break; }
            }
            if (state == ObjectState.Started)
            {
                applicationPool.Start();
                WL("Application Pool {0}'s state has gone from {1} to {2}", applicationPool.Name, state, applicationPool.State);
            }
            else
            {
                WL("Error starting Application Pool {0}: Application Pool never stopped", applicationPool.Name);
            }

            break;
        case ObjectState.Stopped:
        case ObjectState.Stopping:
            WL("Application Pool {0} was already in a {1} state and has not been modified", applicationPool.Name, state);
            break;
        default:
            WL("Error stopping Application Pool {0}: Unexpected ObjectState \"{1}\"", applicationPool.Name, state);
            break;
    }

    state = applicationPool.State;
    for (int i = 0; i < 180 && state != ObjectState.Stopped; i++)
    {
        WL("Application Pool {0}'s state is {1}.  Waiting for state to become Stopped", applicationPool.Name, state);
        Thread.Sleep(500);
        state = applicationPool.State;
    }
    applicationPool.ProcessModel.ShutdownTimeLimit = previousShutdownTimeLimit;
}    
Run Code Online (Sandbox Code Playgroud)

为什么ApplicationPool.ProcessModel.ShutdownTimeLimit似乎不会影响IIS实际终止应用程序池所需的时间?在我尝试回收应用程序池时,是否有其他应用程序不接收503错误?

Dar*_*ryl 7

John Koerner的回答肯定有助于我指出正确的方向.使用Recycle会删除503错误.诀窍是如何杀死无限循环.

以下是您必须采取的步骤,以便回收应用程序池以终止进程并遵循ApplicationPool.ProcessModel.ShutdownTimeLimit属性:

  1. 创建一个ServerManager对象
  2. 循环访问ServerManager对象上的ApplicationPools,直到找到您关心的appPool.提示:ApplicationPools.First(p => p.Name =="DefaultAppPool")是一个有用的功能
  3. 更新ApplicationPool.ProcessModel.ShutdownTimeLimit
  4. 在ServerManager对象上调用CommitChanges().注意:您提交更改的ServerManager对象必须是您用于获取ApplicationPool对象的对象,您对其进行了更改.你不能只做新的ServerManger().CommitChanges();
  5. 睡一秒钟,以便在IIS中读取配置值.此时,您应该在IIS中看到ApplicationPool上的值更改
  6. 在ApplicationPool上调用Recycle或Stop

在回收ApplicationPool时,IIS有点奇怪,因为新的w3wp.exe ApplicationPool进程将立即启动,但旧的应用程序池将等待ApplicationPool.ProcessModel.ShutdownTimeLimit中的秒数关闭.然后它会将仍在运行的任何内容移动到新进程.但是如果你再次回收它,它将杀死无限循环(在ShutdownTimeLimit中等待适当的时间之后).

总而言之,正确提交更改,等待它们生效,然后执行循环,然后再次执行它,如果你有一个想要杀死的无限循环.

我已经发布了源代码,并最终可执行这里在我的博客.