IIS Application Pool recycling in IIS 6 is a crutch for poorly performing code and is frequently misunderstood and overused. However, if you do have a need to use it and want to minimize the hit of your applications in that AppPool spinning up again on the next request, you can use the following code to determine when it recycles.
First, you need to configure IIS to enable reporting AppPool recycle events. This is off by default. This can easily be done using WMI and C#:
using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using System.Text;
namespace LogIISRecycleEvents {
class WmiUtils {
public static void SetLogEventsOnRecycle( RecycleOnEventsTypes types ) {
DirectoryEntry rootEntry = new DirectoryEntry( "IIS://localhost/W3SVC" );
foreach( DirectoryEntry siteEntry in rootEntry.Children ) {
if( siteEntry.SchemaClassName == "IIsApplicationPools" ) {
siteEntry.Properties["LogEventOnRecycle"].Value = (int) types;
siteEntry.CommitChanges();
}
siteEntry.Dispose();
break;
}
rootEntry.Dispose();
}
}
[Flags]
enum RecycleOnEventsTypes {
PrivateMemory = 128,
ConfigChange = 64,
OnDemand = 32,
IsapiUnhealthy = 16,
Memory = 8,
Schedule = 4,
Requests = 2,
Time = 1,
None = 0,
All = PrivateMemory |
ConfigChange |
OnDemand |
IsapiUnhealthy |
Memory |
Schedule |
Requests |
Time
}
}
Next you need to listen for these events. I'm not sure whether the IIS WMI provider supports sending WMI Events or not, but I do know it writes entries to the System Event Log. Listening to the System Event Log is easy and all you need to do is wait for the right event to come through:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows.Forms;
namespace LogIISRecycleEvents {
static class Program {
[STAThread]
static void Main() {
WmiUtils.SetLogEventsOnRecycle( RecycleOnEventsTypes.All );
EventLog log = new EventLog( "System" );
log.EntryWritten += new EntryWrittenEventHandler( log_EntryWritten );
log.EnableRaisingEvents = true;
Console.WriteLine( "Press enter to finish" );
Console.ReadLine();
log.Close();
}
static void log_EntryWritten( object sender, EntryWrittenEventArgs e ) {
if( e.Entry.Source == "W3SVC" && e.Entry.EventID == 1075 &&
e.Entry.EntryType == EventLogEntryType.Information &&
e.Entry.Message.Contains( "worker process" ) &&
e.Entry.Message.Contains( "recycle" ) ) {
Console.WriteLine( "AppPool has recycled!" );
}
}
}
}
Finally, you may have to change what criteria you're searching the EventLogEntry for. As you can see I'm looking at Event Type, Event ID and looking for certain words in the message to indicate the AppPool has recycled. You could use regular expressions to find the specific AppPool name as well.
What to do with this? Create a WebRequest and request your application's default web page and that will force the application to spin up and the next user to your site won't have to wait.