Fixing ASP.NET “Keep Alive”

18 June 2009 –

One issue that has plagued ASP.NET developers for several years now is IIS’ default behavior to shut down the .NET worker process after an idle time (usually 20 minutes). Since ASP.NET’s biggest bottleneck is usually the application startup (compiling ASPX files and loading assemblies into the AppDomain), this means the first visitor to your site after 20+ minutes of no activity can have a very long wait before that page comes back. Embarrassingly long, for you. Subsequent pages come through at the speed you know your site is capable of, but the first impression is done and gone.

If you control the web server, this isn’t a big deal. A simple config change in IIS6 or IIS7 will keep the worker process alive – and your site code in memory, waiting to be served - indefinitely.

But plenty of sites run on shared hosting. In that case, you don’t have any real access to IIS settings. It’s also not really in the interest of your shared hosting provider to offer to keep your site in memory any more than it absolutely needs to be. So what to do? There is a handful of services which offer to hit your site every x minutes to keep IIS from killing your application. Those just don’t seem right, though. Keeping an application alive should be something we have very granular control over – not some one-off service that might disappear tomorrow.

So I wrote a little class that will let an ASP.NET application decide when and whether to “keep alive” itself. Nothing special, really – it puts an object into cache for 10 minutes, and when the 10 minutes are up, the object requests a page in your site through IIS and re-inserts itself into the cache for 10 more minutes.

As long as your application wants to keep itself alive, it can call KeepAlive.Start(url). Just pass in any URL in your site (e.g. "http://www.rexmorgan.net/journal"). You can check IsKeepingAlive to see if your app is currently keeping itself alive. If you want to stop, call KeepAlive.Stop(). (Of course, that won’t actually kill your app – just allows IIS to eventually kill the process if it goes idle).

Here’s the code. If you find it useful, let me know! Cheers:


public class KeepAlive
{
     private static KeepAlive instance;
     private static object sync = new object();
     private string _applicationUrl;
     private string _cacheKey;

     private KeepAlive(string applicationUrl)
     {
         _applicationUrl = applicationUrl;
         _cacheKey = Guid.NewGuid().ToString();
         instance = this;
     }

     public static bool IsKeepingAlive
     {
         get
         {
             lock (sync)
             {
                 return instance != null;
             }
         }
     }

     public static void Start(string applicationUrl)
     {
         if(IsKeepingAlive)
         {
             return;
         }
         lock (sync)
         {
             instance = new KeepAlive(applicationUrl);
             instance.Insert();
         }
     }

     public static void Stop()
     {
         lock (sync)
         {
             HttpRuntime.Cache.Remove(instance._cacheKey);
             instance = null;
         }
     }

     private void Callback(string key, object value, CacheItemRemovedReason reason)
     {
         if (reason == CacheItemRemovedReason.Expired)
         {
             FetchApplicationUr();
             Insert();
         }
     }

     private void Insert()
     {
         HttpRuntime.Cache.Add(_cacheKey,
             this,
             null,
             Cache.NoAbsoluteExpiration,
             new TimeSpan(0, 10, 0),
             CacheItemPriority.Normal,
             this.Callback);
     }

     private void FetchApplicationUrl()
     {
         try
         {
             HttpWebRequest request = HttpWebRequest.Create(this._applicationUrl) as HttpWebRequest;
             using(HttpWebResponse response = request.GetResponse() as HttpWebResponse)
             {
                 HttpStatusCode status = response.StatusCode;
                 //log status
             }
         }
         catch (Exception ex)
         {
             //log exception
         }
     }
}
3 Comments
Reply to this comment
Joe – 19 June 2009

I put this in my javascript and it doesnt run what am I doing wrong

Reply to this comment
Daniel Plomp – 26 August 2009

Hi, Where should I place this code inside my app to run it? Daniel

Reply to this comment
Barbaros – 21 October 2009

You should put these codes into a .cs file then call the method in global_asax application_start

© 2002-2009 Rex Morgan.
Content available under a Creative Commons license.
Site code and design may not be reproduced.