Azure Web App deployment slots are used to help roll out new versions of an app without downtime or cold start activation. New version is typically deployed to a staging slot, then after testing and final verification it gets swapped into a production slot. During the swap operation the Web App’s worker process may get restarted in order for some settings to take effect. Even though the swap does not proceed until the restarted worker process comes back online on every VM instance, it may still not be enough for application to be completely ready to take on production traffic. This post explains how you can use the recently enabled Application Initialization Module to completely warm up your application prior to swapping it into production.
First of all it is necessary to explain the sequence of actions that happens when a staging slot is swapped into production. When the Swap button is clicked in Azure Portal or a corresponding management API is called:
- The App Settings and Connection Strings that are marked as “Slot” are read from the Production slot and applied to the site in the Staging slot. That causes the site’s worker process to be restarted for those changes to take effect and become visible as process environment variables;
- Then the site in the staging slot gets warmed up. To warm up the site an HTTP request is made to the root directory of the site to every VM instance where site is supposed to run. The warm up request has a User-Agent header set to “SiteWarmup”;
- After warm up has completed the host names for the sites in production and staging slots get swapped. Now the site that has been warmed up in the staging slot starts getting production traffic and the site that used to be in the production slot is now in the staging slot
- The site that is now in the staging slot gets updated with the App Settings and Connection Strings associated with the staging slot. That causes restart of that site, but it is not in production slot any more so restart is harmless.
Sometimes hitting the site’s root URL is not enough to completely warm up the application. For example it maybe necessary to hit all important routes in an ASP.NET MVC app or to pre-populate the in-memory cache. That is where the Application Initialization Module can help.
Let’s use a simple example to demonstrate how a Web App can be warmed up in the deployment slot during the swap operation. First let’s create a site and a staging deployment slot:
Next let’s set some slot settings on the App and its staging slot. These slot settings will cause the App’s worker process to restart during swap.
For the actual app code I used two simple PHP files: index.php and warmup-cache.php. The index.php is served when site’s root URL is requested. The warmup-cache.php is my “cache warmup” code that takes long time to run (emulated by sleep() command). In real application that can be the script that makes database queries to fill up the cache.
Finally I also have a web.config file which configures AppInit module:
<system.webServer> <applicationInitialization > <add initializationPage="/warmup-cache.php" hostName="appinit-warmup.azurewebsites.net"/> </applicationInitialization> <system.webServer>
In the applicationInitialization section I can specify multiple URL paths that need to be requested in order to warm up my application. In my case I only need to hit one URL. Also notice that I can specify the host name to use for the warm up requests (this is optional and if not specified the “localhost” will be used as a host name).
The following steps are just for verification/debugging purposes. There is no need to perform them when using AppInit module. In fact enabling them for your production site may considerably slow it down.
To confirm that the warmup-cache.php is actually requested during the swap I will use Failed Request Tracing. It can be enabled from Azure Portal:
However, that will trace only failed requests. I need it to trace all requests. For that I add the following section to the web.config file:
<tracing> <traceFailedRequests> <clear/> <add path="*"> <traceAreas> <add provider="WWW Server" areas="Authentication,Security,Filter,StaticFile,CGI,Compression,Cache,RequestNotifications,Module,Rewrite,iisnode" verbosity="Verbose" /> </traceAreas> <failureDefinitions statusCodes="200-600" /> </add> </traceFailedRequests> </tracing>
The important attribute here is statusCodes which specifies that requests with status codes between 200 and 600 should be logged.
Now let’s run the swap command.
During the swap operation the application is restarted and the first warm up request is made to the root directory of the web app. That starts the AppInit module which makes a request to warmup-cache.php URL and waits until it completes. Only after that request competes the swap operation proceeds to the next step and swaps the host names so that the warmed up site starts getting production traffic. Because of that the swap operation takes longer time to complete.
After the swap completed we can analyze the Request Tracing logs to confirm that the warmup-cache.php URL has been hit prior to the swap. Note that we need to get those log files from the site in the production slot now.
Looking through the logs we can see the following:
- The first warm up request is made to the web site. Notice the user agent value set to “SiteWarmup”:
- Another log file shows that the appInit module has started and made an HTTP request to the warmup-cache.php around the same time. That request has the host name I specified in the web.config file. Also the user-agent is different.
As expected that request took around 30 seconds.
That simple example demonstrates how to use IIS Application Initialization Module with Azure Web App deployment slots to ensure that the application in the slot is completely warmed up.