Reputation: 461
I’m currently dealing with very annoying performance problems after deploying an ASP.NET MVC4 application to Microsoft Azure. Right after restarting the app (or after a few minutes of inactivity) some pages take about 15 seconds to load for the first time. After this, even when clearing the clientside cache those pages will load in about 2 seconds (which is still in need of improvement but way better than 15 seconds, which is a huge user experience killer).
Here’s what I’ve already tried so far:
Since none of the bullets above solved my issue I tried out to write a keppalive-Job using Quartz.NET that regularly requests the website like this:
new System.Net.WebClient().OpenRead("https://foo.azurewebsites.net");
(In my case, I think the effect is more or less the same as declaring initializationPages within Web.Config as mentioned here, isn’t it?)
The result: It works, but just for this specific URL. Maintaining a list of every possible route definitely isn't the way to go.
Have you ever dealt with this issue? I’d highly appreciate your inputs!
Upvotes: 1
Views: 828
Reputation: 461
In addition to the accepted answer I wanted to explain in detail how I finally dealt with this issue. Maybe this may help someone else in future. I wrote some code to warmup the application on startup by simply triggering a web-request on critical sites (I've made the experience that this needs to be done for every single page. Just warming up the root address won’t suffice).
private void WarmUp()
{
var baseUrl = "https://foo.azurewebsites.net";
/**
* Requests to protected pages need to be authenticated and authorized, otherwise the JIT-Compile won't work
* For ASP.NET apps that are using FormsAuthentication just send a POST-request as you normally would do using a html form,
* then grab the cookie you get in the response and pass it to the subsequent requests
* */
var email = "[email protected]";
var password = "verysecure";
var cookies = new CookieContainer();
var webRequest = WebRequest.Create($"{baseUrl}/Account/Login") as HttpWebRequest;
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.CookieContainer = cookies;
var requestWriter = new StreamWriter(webRequest.GetRequestStream());
requestWriter.Write($"user={email}&password={password}");//Small example for brevity. Don't forget to extract the requestVerificationToken in production :-)
requestWriter.Close();
webRequest.GetResponse().Close();
var urls = new[] {
baseUrl,
$"{baseUrl}/Home/Contact",
$"{baseUrl}/Protected/Stuff",
//...
};
foreach (var url in urls)//trigger web-requests
{
webRequest = WebRequest.Create(url) as HttpWebRequest;
webRequest.CookieContainer = cookies;
webRequest.GetResponse().Close();
}
}
This triggers the time-consuming JIT-stuff for us when the app starts/after deployment, thus preventing our users to experience horrible performance when requesting the page. If your app’s pricing plan is S1 or higher you can improve performance even more using deployment slots. They allow you to warmup the app even before deploying to production.
In my case (reserved pricing tier, B1), I think it is enough to run the code above once within Application_Start, since «Always on» should prevent my app’s worker process from being shut down automatically in case the site doesn’t get any traffic for a set period of time (If your app is running on shared resources make sure to keep alive your app using a Cron job or something similar).
Upvotes: 1
Reputation: 4440
It has been some time since I was working in an organization that hosted on azure but they used to have an option that you could configure labeled "Always On" which would in effect be the equivalent of setting the idle timeout to zero on a application pool and keep your application loaded into memory. Otheriwise without traffic then your site will be unloaded and forced to JIT upon first hit (kinda like after initial deploy).
I've read about others creating mock http request to their sites to keep the traffic up going and avoid the unload from memory when they were subscribed to the lower priced tiers that did not offer the "always on" option.
Edit: Here is another SO post addressing it: App pool timeout for azure web sites
Upvotes: 3