Fixing slow initial load for IIS

asp.net.Net 4.0Iis 7.5

asp.net Problem Overview


IIS has an annoying feature for low traffic websites where it recycles unused worker processes, causing the first user to the site after some time to get an extremely long delay (30+ seconds).

I've been looking for a solution to the problem and I've found these potential solutions.

A. Use the Application Initialization plugin

B. Use Auto-Start with .NET 4

C. Disable the idle-timeout (under IIS Reset)

D. Precompile the site

I'm wondering which of these is preferred, and more importantly, why are there so many solutions to the same problem? (My guess is they aren't, and I'm just not understanding something correctly).

Edit

Performing C seems to be enough to keep my site warmed up, but I've discovered that the real root of my site's slowness has to do with Entity Framework, which I can't seem to figure out why it's going cold. See this question, which unfortunately hasn't been answered yet has been answered!

I eventually just had to make a warm up script to hit my site occasionally to make sure it stayed speedy.

asp.net Solutions


Solution 1 - asp.net

Options A, B and D seem to be in the same category since they only influence the initial start time, they do warmup of the website like compilation and loading of libraries in memory.

Using C, setting the idle timeout, should be enough so that subsequent requests to the server are served fast (restarting the app pool takes quite some time - in the order of seconds).

As far as I know, the timeout exists to save memory that other websites running in parallel on that machine might need. The price being that one time slow load time.

Besides the fact that the app pool gets shutdown in case of user inactivity, the app pool will also recycle by default every 1740 minutes (29 hours).

From technet:

> Internet Information Services (IIS) application pools can be > periodically recycled to avoid unstable states that can lead to > application crashes, hangs, or memory leaks.

As long as app pool recycling is left on, it should be enough. But if you really want top notch performance for most components, you should also use something like the Application Initialization Module you mentioned.

Solution 2 - asp.net

Web Hosting Challenge

You have to remember that none of the machine configuration options are available if you are hosted on a shared server as many of us (smaller companies and individuals) are.

ASP.NET MVC Overhead

My site takes at least 30 seconds when it hasn't been hit in over 20 minutes (and the web app has been stopped). It is terrible.

Another Way to Test Performance

There's another way to test if it is your ASP.NET MVC start up or something else. Drop a normal HTML page on your site where you can hit it directly.
If the problem is related to ASP.NET MVC start up then the HTML page will render almost immediately even when the web app hasn't been started.
That's how I first recognized that the problem was in the ASP.NET MVC startup. I loaded an HTML page at any time and it would load blazing fast. Then, after hitting that HTML page I'd hit one of my ASP.NET MVC URLs and I'd get the Chrome message "Waiting for raddev.us..."

Another Test With Helpful Script

After that I wrote a LINQPad (check out http://linqpad.net for more) script that would hit my web site every 8 minutes (less than the time for the app to unload -- which should be 20 minutes) and I let it run for hours.

While the script was running I hit my web site and every time my site came up blazingly fast. This gives me a good idea that most likely the slowness I was experiencing was because of ASP.NET MVC startup times.

Get LinqPad and you can run the following script -- just change the URL to your own and let it run and you can test this easily. Good luck.

NOTE: In LinqPad you'll need to press F4 and add a reference to System.Net to add the library which will retrieve your page.

ALSO : make sure you change the String URL variable to point at a URL that will load a route from your ASP.NET MVC site so the engine will run.

System.Timers.Timer webKeepAlive = new System.Timers.Timer();
Int64 counter = 0;
void Main()
{
    webKeepAlive.Interval = 5000;
    webKeepAlive.Elapsed += WebKeepAlive_Elapsed;
	webKeepAlive.Start();
}

private void WebKeepAlive_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
  	webKeepAlive.Stop();
	try
	{
        // ONLY the first time it retrieves the content it will print the string
		String finalHtml = GetWebContent();
		if (counter < 1)
		{
			Console.WriteLine(finalHtml);
		}
		counter++;
	}
	finally
	{
		webKeepAlive.Interval = 480000; // every 8 minutes
		webKeepAlive.Start();
	}
}

public String GetWebContent()
{
	try
	{
    String URL = "http://YOURURL.COM";
	WebRequest request = WebRequest.Create(URL);
	WebResponse response = request.GetResponse();
	Stream data = response.GetResponseStream();
	string html = String.Empty;
	using (StreamReader sr = new StreamReader(data))
	{
		html = sr.ReadToEnd();
	}
	Console.WriteLine (String.Format("{0} : success",DateTime.Now));
	return html;
	}
	catch (Exception ex)
	{
		Console.WriteLine (String.Format("{0} -- GetWebContent() : {1}",DateTime.Now,ex.Message));
		return "fail";
	}
}

Solution 3 - asp.net

Writing a ping service/script to hit your idle website is rather a best way to go because you will have a complete control. Other options that you have mentioned would be available if you have leased a dedicated hosting box.

In a shared hosting space, warmup scripts are the best first level defense (self help is the best help). Here is an article which shares an idea on how to do it from your own web application.

Solution 4 - asp.net

I'd use B because that in conjunction with worker process recycling means there'd only be a delay while it's recycling. This avoids the delay normally associated with initialization in response to the first request after idle. You also get to keep the benefits of recycling.

Solution 5 - asp.net

See this article for tips on how to help performance issues. This includes both performance issues related to starting up, under the "cold start" section. Most of this will matter no matter what type of server you are using, locally or in production.

https://blogs.msdn.microsoft.com/b/mcsuksoldev/2011/01/19/common-performance-issues-on-asp-net-web-sites/

> If the application deserializes anything from XML (and that includes web services…) make sure SGEN is run against all binaries involved in deseriaization and place the resulting DLLs in the Global Assembly Cache (GAC). This precompiles all the serialization objects used by the assemblies SGEN was run against and caches them in the resulting DLL. This can give huge time savings on the first deserialization (loading) of config files from disk and initial calls to web services. http://msdn.microsoft.com/en-us/library/bk3w6240(VS.80).aspx

> If any IIS servers do not have outgoing access to the internet, turn off Certificate Revocation List (CRL) checking for Authenticode binaries by adding generatePublisherEvidence=”false” into machine.config. Otherwise every worker processes can hang for over 20 seconds during start-up while it times out trying to connect to the internet to obtain a CRL list. http://blogs.msdn.com/amolravande/archive/2008/07/20/startup-performance-disable-the-generatepublisherevidence-property.aspx

>http://msdn.microsoft.com/en-us/library/bb629393.aspx

> Consider using NGEN on all assemblies. However without careful use this doesn’t give much of a performance gain. This is because the base load addresses of all the binaries that are loaded by each process must be carefully set at build time to not overlap. If the binaries have to be rebased when they are loaded because of address clashes, almost all the performance gains of using NGEN will be lost. http://msdn.microsoft.com/en-us/magazine/cc163610.aspx

Solution 6 - asp.net

A good option to ping the site on a schedule is to use Microsoft Flow, which is free for up to 750 "runs" per month. It is very easy to create a Flow that hits your site every hour to keep it warm. You can even work around their limit of 750 by creating a single flow with delays separating multiple hits of your site.

https://flow.microsoft.com

Solution 7 - asp.net

I was getting a consistent 15 second delay on the first request after 4 minutes of inactivity. My problem was that my app was using Windows Integrated Authentication to SQL Server and the service profile was in a different domain than the server. This caused a cross-domain authentication from IIS to SQL upon app initialization - and this was the real source of my delay. I changed to using a SQL login instead of windows authentication. The delay was immediately gone. I still have all the app initialization settings in place to help improve performance but they may have not been needed at all in my case.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionCavyn VonDeylenView Question on Stackoverflow
Solution 1 - asp.netRăzvan Flavius PandaView Answer on Stackoverflow
Solution 2 - asp.netraddevusView Answer on Stackoverflow
Solution 3 - asp.netDavid ChelliahView Answer on Stackoverflow
Solution 4 - asp.netKitView Answer on Stackoverflow
Solution 5 - asp.netmarknuzzView Answer on Stackoverflow
Solution 6 - asp.netLMKView Answer on Stackoverflow
Solution 7 - asp.netDroobieView Answer on Stackoverflow