Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keep an ASP.NET IIS website responsive when time between visits is long

Tags:

.net

asp.net

iis

After years of ASP.NET development I'm actually quite surprised that I can't seem to find a satisfying solution for this.

Why does an IIS ASP.NET site always seem to fall asleep (for 2-6 seconds) after a certain time of inactivity (after several hours), during which no HTTP response is sent from server to client. This happens on any type of site, one page or many, db or not, regardless the settings. How can I fix this?

During the wait time, the server is not busy and there are no high peaks or (.NET) memory shortages. My guess is, it has to do with Windows moving the IIS process to the background and its memory to the page file, but I'm not sure. Anybody any idea?

EDIT: one solution is to send some HTTP request once an hour or so, but I hope for something more constructive.
EDIT: what I meant is: after hours of inactivity, it pauses several seconds on any new HTTP request.

like image 407
Abel Avatar asked Nov 03 '09 21:11

Abel


2 Answers

The default timeout for IIS is 20 minutes. What this means is if your ASP.NET application does not receive any new requests for 20 minutes, it will shut down the worker process. It can take a considerable amount of time to warm up the process from nothing - loading assemblies into memory, precompilation, etc.

(Edit: I put together a simple helper class that resolves the standard timeout issue - basically the web application "pokes" itself every so often to keep the process alive. The ideal approach is to change the setting in IIS, but for servers where this is not possible, my class works quite well. - Code at the bottom)

While the worker process is still alive, it should not be deprioritized. Certainly not as quickly as you're describing. It is possible you could relying on items that are cached for a very short period of time, and are falling out when they've not been requested for more than a few seconds. Without knowing more about the details of your application, it's impossible to say.

As usual, profiling your application is the only way to yield concrete information. Using a product like ANTS will help you determine where in the code your application is spending the most time, so you can isolate where the "hang" is occurring.

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

Usage (perhaps in App_Start):

KeepAlive.Start("http://www.yoursite.com/");
like image 167
Rex M Avatar answered Oct 21 '22 17:10

Rex M


If you're using IIS 7 there is an IIS plugin call Application Warm Up from the IIS team that will help keep everything toasty

I've written a blog post about my experiences using it.

like image 1
Doug Avatar answered Oct 21 '22 17:10

Doug