9
votes

When the website is accessed by the first few users the performance is very slow.

The Windows Azure setup is using IIS 7.0 so the warm up initialization module is not an option.

Is there a way to "warm up" the website so that this performance speed is not an issue?

I have looked at this: Controlling Application Pool Idle Timeouts in Windows Azure, but not sure if this will still cause an issue when Azure recycles the application pool every 29 hours approx.

UPDATE:

The deployment is 1 web role that contains multiple websites. Is it possible to do the pre-compilation for this? or use web roles as is suggested in one of the answers below?

EDIT:

As @Igorek has stated below regarding using Web Roles that auto-load themselves during Role's startup which is possible in the setup I have. Does anybody have an example of how to achieve this?

4
how about having a curl or wget set of commands hitting several url in your website? - rene
@rene Would this be appropriate for an application with a high number (thousands?) of pages, each having several code paths? - Paul Fleming
@flem I guess not... but I didn't read that in the question...assuming the root cause of the problem is mainly related to getting things from disk in memory (assemblies, indexes/tables) you can have a couple of url's that make sure all components are hit. I'm not saying it is easy or simple. - rene

4 Answers

5
votes

I have looked at this: Controlling Application Pool Idle Timeouts in Windows Azure, but not sure if this will still cause an issue when Azure recycles the application pool every 29 hours approx.

It won't cause an issue when Azure recycles the app pool, but you can also add to that startup task to prevent/increase the application pool recycling time.

Try this:

Define the task in your ServiceDefinition:

<Startup>
    <Task commandLine="startup\disableTimeout.cmd" executionContext="elevated" />
</Startup>

Then have your cmd file with the following code (just put it into notepad, then save as a .cmd file):

%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00

%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.recycling.periodicRestart.time:00:00:00

Two things to make sure of:

1) Make sure you save the file with ANSI encoding.
2) When you've added that script into Visual Studio, make sure you select "Copy Always" as the "Copy to Output Directory" option in the properties.

2
votes

Are you precompiling the application? By default, the application after being deployed still needs to be compiled for the first time. Depending on the size of the application, compile can take multiple seconds http://msdn.microsoft.com/en-us/library/399f057w(v=vs.85).aspx

2
votes

When the first HTTP request arrives a lot of extra work is actually done - application pool is started, all needed assemblies are found, all assemblies shipped as MSIL are compiled into machine code, then the necessary ASP.NET views are precompiled (unless you deploy them precompiled, but it's quite hard with Azure tools so I guess you don't do that). This all takes some time and so the unlucky first users have to wait.

The workaround is to warm up the site from inside role entry point OnStart() - make it precompile the site and then send an HTTP request to localhost.

0
votes

mattytommo's answer works perfectly fine, but I prefer to achieve the same goal programmatically instead of relying on a cmd file. You can do it in 3 steps:

Step 1: You have to install NuGet package Microsoft.Web.Administration. The package contains library needed to control IIS from your application code.

Step 2: Then you just add a call to this method from Web Role's RoleEntryPoint. If it does not exist, just add a class that inherits from RoleEntryPoint.

private void ConfigureAppPools()
{
    using (ServerManager serverManager = new ServerManager())
    {
        foreach (var appPool in serverManager.ApplicationPools)
        {
            appPool.ProcessModel.IdleTimeout = TimeSpan.Zero;
            appPool.Recycling.PeriodicRestart.Time = TimeSpan.Zero;
        }
        serverManager.CommitChanges();
    }
}

This code just configures all application pools on the machine to never recycle or timeout.

Step 3: For this to work, it is also needed to add this one line to ServiceDefinition.csdef:

  <WebRole name="YourWebRoleName" vmsize="ExtraSmall">
    ...
    <Runtime executionContext="elevated" />
    ...
  </WebRole>

This makes sure your web RoleEntryPoint's OnStart() method is executed with elevated permissions. Other parts of your code will not be affected, so that's not a problem from security standpoint.

That is all. Problem with slow loads is now solved :)