How to tell why an IIS application pool is recycled How to tell why an IIS application pool is recycled asp.net asp.net

How to tell why an IIS application pool is recycled


Without access to the event logs (because you're in a shared hosting environment) the most information you're going to get is from the Application_End event and by asking the HttpRuntime (via reflection) for the values of one or two private members that are sadly not exposed publicly.

To do this add the following code to your Application_End event:

BindingFlags staticFlags =     BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.GetField;BindingFlags instanceFlags =     BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.GetField;HttpRuntime runtime = (HttpRuntime)typeof(System.Web.HttpRuntime)                        .InvokeMember("_theRuntime", staticFlags, null, null, null);if(runtime != null) {    string shutDownMessage = (string)runtime.GetType()         .InvokeMember("_shutDownMessage", instanceFlags, null, runtime, null);    string shutDownStack = (string)runtime.GetType()         .InvokeMember("_shutDownStack", instanceFlags, null, runtime, null);    // Log shutDownMessage & shutDownStack somewhere}

If I shutdown or recycle my app's application pool I see the following:

HostingEnvironment initiated shutdownHostingEnvironment caused shutdown -       at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)   at System.Environment.get_StackTrace()   at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()   at System.Web.Hosting.HostingEnvironment.InitiateShutdownWithoutDemand()   at System.Web.Hosting.PipelineRuntime.StopProcessing()

That's probably about as good as it gets.

Update:

I couldn't remember where I found this code but Drew helpfully reminded me it was from a Scott Guthrie blog post.

There are some other private members that could be useful such as:

private ApplicationShutdownReason _shutdownReason;

You can examine these fields in .NET Reflector (if you still have a copy that isn't time-bombed) or one of the alternatives (Open Source Alternatives to Reflector?).


Research - 1

Firstly I tried using System.Web.ProcessModelInfo.GetCurrentProcessInfo() and System.Web.ProcessModelInfo.GetHistory(int). The results of these methods return info such as the PID, start time, age, status, and peak memory usage. Unfortunately these were unavailable in my hosting environment:

HttpException 0x80004005 - Process metrics are available only when the ASP.NET process model is enabled. When running on versions of IIS 6 or newer in worker process isolation mode, this feature is not supported.

This approach might work for others though, so if you're in this situation, give it a shot.

Research - 2

The property System.Web.Hosting.HostingEnvironment.ShutdownReason is an enum with lots of values, but unfortunately all the cases I outline in my question are bundled into a single enum value:

ApplicationShutdownReason.HostingEnvironment: The hosting environment shut down the application domain.

Research - 3

ScottGu has an approach on his blog (which is the same code Kev posted) that uses reflection to access internal state of the HttpApplication. Unfortunately in this case it only reports the same detail as #2 above:

_shutDownMessage =  HostingEnvironment initiated shutdown  HostingEnvironment caused shutdown_shutDownStack =  at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)  at System.Environment.get_StackTrace()  at System.Web.Hosting.HostingEnvironment.InitiateShutdownInternal()  at System.Web.Hosting.HostingEnvironment.InitiateShutdownWithoutDemand()  at System.Web.Hosting.PipelineRuntime.StopProcessing()


This is a really late answer, but I hope it can provide extra insight for those having similar problems (IIS 7.x or above).

1. Finding when application pool is starting to shutdown - the following code can be used to find out when the application pool start its shutdown. Actual shutdown occurs in a maximum of Shutdown limit (seconds, default 90) after this event.

public class ApplicationPoolService : IApplicationPoolService{    public bool IsShuttingDown()    {        return System.Web.Hosting.HostingEnvironment.ShutdownReason != ApplicationShutdownReason.None;    }    public ApplicationShutdownReason GetShutdownReason()    {        return System.Web.Hosting.HostingEnvironment.ShutdownReason;    }}public class HostingEnvironmentRegisteredObject : IRegisteredObject{    public void Stop(bool immediate)    {        // second call is done when the Stop is imminent         if (immediate)            return;        var reason = appPoolService.GetShutdownReason().ToString();        logger.Log(LogLevel.Info, $"HostingEnvironmentRegisteredObject.stop called with shutdown reason {reason}");    }}// this code should be placed in global.asax.csprotected void Application_Start(){    HostingEnvironment.RegisterObject(new HostingEnvironmentRegisteredObject());}

This helps to find the general reason and exactly when it was triggered. In your case, I think HostingEnvironment is the value. Unfortunately, the underlying cause is not unique. It can be periodic recycle, recycle due to memory limit (most probable reason in OP's question), recycle due to fixed hour etc.

2. Finding the exact cause - one way to find out the exact cause is to search for it in the EventLog. If this is not accessible, it can be requested from the hosting provider by providing the following details to narrow their search.

  • Exact time of shutdown initiation
  • Event log filter:
    • Event sources = WAS
    • Event level = Information
    • Logged = custom range including exact time of shutdown +/- 1 minute or so

Event log should return more relevant information like the ones below:

A worker process with process id of 'xxx' serving application pool 'xxx' has requested a recycle because it reached its scheduled recycle time.


A worker process with process id of 'xxx' serving application pool 'xxx' has requested a recycle because it reached its virtual memory limit.