简体   繁体   中英

Issues Programatically Recycling Application Pools in IIS7

I created a C# application to recycle all application pools in IIS, one at a time, using the Microsoft.Web.Administration.ApplicationPool class. There is no method on ApplicationPool to restart the app pool (please correct me if I'm wrong), so I figured you'd just have to do a stop, and then a start. This was working fine for the most part, until we started getting some threads in an app pool that were stuck in an infinite loop.

By default IIS has a 90 second "Shutdown Time Limit", where it waits 90 seconds before it terminates any threads still running, so I'd call ApplicationPool.Stop(), and it would take 90 seconds until IIS terminated the app pool, before it's state would be stopped and I could tell it to start again. Anything that would attempt to hit any applications using that app pool, would get a 503 error response for those 90 seconds until I could start the pool again.

I decided to try and change the "Shutdown Time Limit" programmatically to 5 seconds to decrease the number of apps that would get the 503 error, but IIS is still waiting 90 seconds before it terminates the Application Pool. Below is my function to shutdown the application pool:

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;
}    

Why doesn't the ApplicationPool.ProcessModel.ShutdownTimeLimit seem to affect how long it takes for IIS to actually kill the Application Pool? Is there anyway to keep other applications from receiving the 503 errors while I'm trying to recycle the application pool?

John Koerner's answer definitely helped point me in the right direction. Using Recycle removes the 503 errors. The trick was how to kill the infinite loop.

Here are the steps you must take in order for the Recycle the App Pool to kill the process and obey the ApplicationPool.ProcessModel.ShutdownTimeLimit property:

  1. Create a ServerManager object
  2. Loop through the ApplicationPools on the ServerManager object till you find the appPool you care about. Tip: ApplicationPools.First(p => p.Name == "DefaultAppPool" ) is a helpful function
  3. Update the ApplicationPool.ProcessModel.ShutdownTimeLimit
  4. Call CommitChanges() on your ServerManager object. NOTE: The ServerManager object you commit the changes on, must be the object that you used to get the ApplicationPool object, that you made changes to. You can't just do new ServerManger().CommitChanges();
  5. Sleep a second so the config value will get read in IIS. At this point, you should see the value change on the ApplicationPool in IIS
  6. Call Recycle or Stop on your ApplicationPool

When Recycling the ApplicationPool, IIS is kind of strange in that a new w3wp.exe ApplicationPool Process will start up immediately, but the old app pool will wait the number of seconds in the ApplicationPool.ProcessModel.ShutdownTimeLimit to shutdown. It will then move anything that is still running over to the new process. But if you recycle it again, it will kill the infinite loop(after it waits the appropriate time in the ShutdownTimeLimit).

So to sum it all up, commit your changes correctly, wait for them to take effect, then perform your recycle, then do it again if you have an infinite loop that you want to kill.

I've posted the source code and final executable here on my blog.

To do a restart on the app pool, you can use the Recycle Method. That probably will not alleviate the 90 second problem though. There may be something in the Recycling object that you could play with to adjust the timeout.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM