Using a Windows Azure startup script to prevent your site from being shutdown

Did you know that, by default, IIS will shutdown your site upon the following events?

a) After being idle for 20 minutes.
b) Every 29 hours (due to recycling).

The first vistor to your site after one of these events will encounter a poor user experience (slow response) whilst a new IIS app pool is initialised.  Note, this IIS behaviour is "inherited" by Azure so read on if you're hosting your site on Azure and care about a consistant user experience.

To prevent this behaviour you can't just go into the IIS manager and make the necessary amendments to the default configuration when your site is hosted on Azure.  Any configuration changes you make in a remote desktop session to your Azure instance(s) will get lost when the Azure fabric controller recycles your instances.

The solution is to make the necessary IIS configuration changes via an Azure statup script as follows:

1) Startup script - add a startup script (batch file) to your web role project.  I like to store mine in \Startup\Startup.cmd.

REM *** Prevent the IIS app pools from shutting down due to being idle.
%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.processModel.idleTimeout:00:00:00

REM *** Prevent IIS app pool recycles from recycling on the default schedule of 1740 minutes (29 hours).
%windir%\system32\inetsrv\appcmd set config -section:applicationPools -applicationPoolDefaults.recycling.periodicRestart.time:00:00:00

*** GOTCHA 1 of 2 - Make sure your startup script is ANSI (not UTF-8) encoded.  I've found good ol' "Visual Notepad" is the best way to achieve this task.  However, I believe Visual Studio has an equivilent File...Save As option also.
*** GOTCHA 2 of 2 - Make sure you select "Copy Always" as the "Copy to Output Directory" option in the properties for your startup script file. 

2) ServiceDefinition.csdef - merge the "Startup" element highlighted below into your ServiceDefinition.csdef.

<?xml version="1.0" encoding="utf-8"?>
<ServiceDefinition name="MyWindowsAzureProject" xmlns="https://schemas.microsoft.com/ServiceHosting/2008/10/ServiceDefinition">
  <WebRole name="MyWebRole" vmsize="Small">
 ...
    <Startup>
      <Task commandLine="Startup\Startup.cmd" executionContext="elevated" />
    </Startup>
  </WebRole>
</ServiceDefinition>

Startup scripts run from "f:\approot" on your Azure instances so bear that in mind if you're using relative folder references.  Personally, I like to make any path referencing as explicit as possible.

Startup scripts are the recommended way to make any pre-requisite installations and/or configuration changes that might be needed by your application.  Mastering startup scripts is essential to performing more complex deployments to Azure.  Whilst it might take a little more effort that the "old way", I'm confident that you'll appreciate the many benefits of the Platform As A Service (PaaS) approach employed by Azure so the additional, incremental effort, is well worth it.

Comments

  • Anonymous
    October 02, 2011
    Hi, I think that GOTCHA 1 will also work with "UTF-8 NO BOM". At least mine scripts work that way ;)

  • Anonymous
    October 31, 2012
    You actually don't need a startup script... you can run elevated by configuring your role with an elevated context... Add <Runtime executionContext="elevated" />  to your ServiceDefinition.csdef file, before you're <Sites> node.