ASP.Net Application Idle Timeout and App Pool Recycling - iis-7

I have the following job schedlued to run every minute using hangfire to try and keep my site alive but it still seems to idle out? I've just checked the hangfire dashboard and looks like the job never ran over the weekend presumembly because no one visited the site (note it's an intranet application)
try
{
var url = "http://xyz.domain.com/myapp"
var request = (HttpWebRequest)WebRequest.Create(url);
request.Timeout = 6000;
request.AllowAutoRedirect = false;
request.Method = "HEAD";
using (var response = request.GetResponse())
{
// TO DO
}
}
catch (Exception ex)
{
logger.Error(ex, "Error in KeepAlive job");
}
Would using webclient be more reliable or is it the same as using HttpWebRequest -something like below:
WebClient webClient = new WebClient();
Stream stream = webClient.OpenRead("http://xyz.domain.com/myapp");

By default, Hangfire Server instance in a web application will not be started until the first user hits your site. Even more, there are some events that will bring your web application down after some time (I’m talking about Idle Timeout and different app pool recycling events). In these cases your recurring tasks and delayed jobs will not be enqueued, and enqueued jobs will not be processed.
This is particulary true for smaller sites, as there may be long periods of user inactivity. But if you are running critical jobs, you should ensure that your Hangfire Server instance is always running to guarantee the in-time background job processing.
http://docs.hangfire.io/en/latest/deployment-to-production/making-aspnet-app-always-running.html

Related

When a Asp.net Web App is recycled in Azure?

We have a asp.net web app with "Always on" that is running a long task. To avoid to run this task two or more time simultaneously, at the beggining of the task a flag is set to database. If this task is forced to shutdown the flag is not removed, and the task is not gonna run again without manual intervention.
I've been looking for if the concept of recycle a website is existing in Azure, I didn't find much about it. I found for example https://stackoverflow.com/a/21841469/1081568 it seems that is never executed recycled, but I find some people complaining about web apps with "always on" set that recycles randomly.
I would like to know in which circumstance an app could be Recycled/shutdown in Azure? Just for maintenance? Azure recycle asp.net webs apps? Or is a concept exclusive of On-Premise servers?
And another question, Is there a way to capture this shutdown/recycle from Azure and stop my running task gracefully if it's running.
Thanks
As far as I know, normally azure will not recycled your web app's resource, if you set web apps with "always on".
If web app's “Always On” setting is off, which means the web site will be recycled after period of inactivity (20 minutes).
And another question, Is there a way to capture this shutdown/recycle from Azure and stop my running task gracefully if it's running.
According to your description, I suggest you could send a kudu restapi request to get the current web app's processid.
If the application restarted, the processid will be changed. By comparing the processid, you could capture this web app is recycled.
More details about how to get the current web app's processid, you could refer to below steps:
1.Set a Deployment credentials in your azure web application as below:
Notice:Remember the user name and password, we will use them to generate the access token
2.Send the request to below url to get the process information.
Url:https://yourwebsitename.scm.azurewebsites.net/api/processes
Code sample:
string url = #"https://yourwebsitename.scm.azurewebsites.net/api/processes";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.Method = "GET";
httpWebRequest.ContentLength = 0;
string logininforation = "username:password";
byte[] byt = System.Text.Encoding.UTF8.GetBytes(logininforation);
string encode = Convert.ToBase64String(byt);
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Basic " + encode);
using (HttpWebResponse response = (HttpWebResponse)httpWebRequest.GetResponse())
{
using (System.IO.StreamReader r = new System.IO.StreamReader(response.GetResponseStream()))
{
string jsonResponse = r.ReadToEnd();
dynamic result = JsonConvert.DeserializeObject(jsonResponse);
dynamic resultList = result.Children();
foreach (var item in resultList)
{
Console.WriteLine(item.name + " : " + item.id);
}
}
}
Result:
You could also find the processid in the portal.
Select your web app --> Process explorer
Image:

Pre-Load Web Application Pages After Deployment to Prevent Slow Loading

We build and deploy our web application to our dev environment automatically every night (using VSTS). When we come into the office in the morning, the first person to access the application has to wait an extended period for each page to load the first time. Subsequent loads are very fast.
The problem has a greater impact in our live environment where, after a deployment, it is potentially an end-user who is the first person to access the application and complain of slowness. To mitigate for this, a member of the team is currently accessing every page of the application manually after deployment to the live environment so that they 'pre-load' every page, which works, but is obviously time-consuming!
I've done a fair bit of searching on the subject, and have configured the appropriate Application Pool in our IIS server (IIS 8.5) so that its Start Mode is set to "AlwaysRunning". I've also edited our applicationHost file and set the appropriate Sites with the preloadEnabled="true" attribute. I did this after reading the instructions in this very helpful Microsoft documentation.
However, if I'm reading that documentation correctly, any pre-loading of the website which might alleviate the issue we're having (and I'm not even certain that this is the kind of pre-loading that I'm thinking of) only takes place when the server, the IIS service of the Application Pool are restarted. This isn't happening in our case. We need the pre-loading to take place following a deployment of the application to the IIS server.
Is there a way to automate this pre-loading?
One way of doing this would be to perform a HTTP request automatically:
As soon as the app was deployed (by running a task from the deploying machine)
Before the application pool has the chance to shut itself down (using Task Scheduler for instance)
Personally, I use a tool that is run in both cases to keep the site warmed up.
Advantages
Robust control over how and when this warm-up is executed.
It's completely independent from any IIS or web.config setup.
Disadvantages
Generates "bogus" log information.
Keeps the app permanently in memory (the Pool would never time-out, essentially wasting server resources for sites with a low # of visitors).
Sample
Such a tool could be a simple console app written as follows:
var taskInfo = new {
Url = "http://www.a-website-to-keep-warm.url",
UseHostHeader = true,
HostHeader = "www.a-website-to-keep-warm.url",
HttpMethod = "head"
};
HttpStatusCode statusCode = HttpStatusCode.Unused;
long contentLength = 0;
try
{
Dictionary<string, string> headers = new Dictionary<string, string>();
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(taskInfo.Url);
webRequest.Method = taskInfo.HttpMethod.ToUpper();
if(taskInfo.UseHostHeader)
webRequest.Host = taskInfo.HostHeader;
using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
{
//did we warm-up the site successfully?
statusCode = webResponse.StatusCode;
contentLength = webResponse.ContentLength;
//optionally read response headers
foreach (string header in webResponse.Headers)
{
headers.Add(header, webResponse.Headers[header]);
}
}
decimal kilobytes = Math.Round(contentLength / 1024M, 1);
Debug.WriteLine($"Got {kilobytes:F1} kB with statuscode: \"{statusCode} \" ...");
}
catch (Exception ex)
{
Debug.WriteLine($"taskInfo failed with exception: {ex.Message}");
}
In my case, I read a bunch of taskInfo objects from a json file and execute them asynchronously every X minutes, making sure X is lower than the Pool-timeout value. It is also run immediately after every deploy.
Because we're not interested in getting the entire content, it uses a HTTP HEAD request instead of GET. Lastly, it supports multiple sites on the same host by adding a Host header to the request.

"An existing connection was forcibly closed by the remote host" sporadic error from HttpWebRequest

I'm having an odd, sporadic problem with a simple test app (Visual Studio console application) that acts as a watchdog for a hosted aspx web site (not app) by sending it simple http requests and timing the response times. I've used this for many weeks in the past without this particular problem. At seemingly random times during the day, my http requests start failing with the above error. They appear to be timeouts since the requests that fail are all taking 60 seconds. After a period of consistent errors as per above (random time periods from a few minutes to 90 minutes in one case) the errros stop and http responses start coming back with no errors at the normal speed (usually about .25s). The watchdog client requests triggers a very simple database lookup, just 1-2 lines of code on the server side. This is hosted at a shared windows hosting web host.
I can also trigger this behavior at will by updating any .cs file on my host site, which, among other things, causes the app pool to recycle. Immediately my watchdog app starts timing out again with the above error.
It smells like some kind of recycled connection problem, since if I simply restart the watchdog app, it works fine and responses start coming back at the normal delay.
I've tried setting request.KeepAlive = false and request.ServicePoint.ConnectionLimit = 1, those did not help.
Another clue, I cannot connect with IIS manager to either of two different websites hosted on this server, which has always worked fine. I'm getting "The underlying connection was closed" trying to connect via IIS Manager. Every time. I have not updated either of the sites in a while, so it wasn't any change of mine.
This is an asp.net 4 website on the backend running on IIS7 with a dedicated app pool in integrated pipeline mode.
Also if I change the sleeptime variable in the watchdog app to something like 30 seconds, the problem doesn't show up. There's some magic number in the range of I believe 10-20 seconds where if the requests are pausing more than that, they never fail.
I think the fact that IIS Manager can't connect is good evidence that something is wrong on the host side independant of my test app but I wanted to cover my bases before opening a support incident... especially since a simple restart of my console app fixes the problem... at least for a while.
class Program
{
//make a simple web request and just return the status code
static string SendHttpMsg(string url, string postData)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(url));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
request.ContentLength = byte1.Length;
//request.KeepAlive = false; //no effect
//request.ServicePoint.ConnectionLimit = 1; //no effect
Stream requestStream = request.GetRequestStream();
requestStream.Write(byte1, 0, byte1.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
response.Close();
return ((int)response.StatusCode).ToString();
}
static void Main(string[] args)
{
int sleeptime = 5000;
string result = "";
while (true)
{
DateTime start = DateTime.Now;
try
{
//this is a very simple call that results in a very simple, fast query in the database
result = SendHttpMsg("http://example.com/somepage.aspx", "command=test");
}
catch (Exception ex)
{
//fancy exception handling here, removed
}
DateTime end = DateTime.Now;
TimeSpan calltime = end - start;
Console.WriteLine(end.ToString() + ", " + calltime.TotalSeconds.ToString("F") + " seconds " + result);
Thread.Sleep(sleeptime);
}
}
}
You could have dangling connections, and in HTTP 1.1 you are limited to 2 connections.
Try changing the HTTP Protocol Version used in the request:
request.ProtocolVersion = HttpVersion.Version10;
If that doesn't work, it could be taking a long time to resolve the proxy settings, which can be fixed by disabling the proxy settings in your application by adding the following to the .config file:
<system.net>
<defaultProxy enabled="false">
<proxy/>
<bypasslist/>
<module/>
</defaultProxy>
</system.net>
If either of the above fixes the problem, I'd recommend adding a try...catch...finally block around your request code, to ensure that each request is properly closed and disposed of (try setting request = null in your finally statement inside the method).

WebRequest fails when executed in Asp.net server side but passes when executed from Windows application

IIS 8 & Windows 8
I have below sample code which I am trying to check whether a url exists, when I ran from console app it works fine, response is obtained, but when executed from server side ASP.net page it throws socket exception.
Sample code:
try
{
Uri uri = new Uri("HTTPS://test");
WebRequest http = HttpWebRequest.Create(uri);
HttpWebResponse response = (HttpWebResponse)http.GetResponse();
Stream stream = response.GetResponseStream();
}
catch (UriFormatException sds)
{
}
catch (IOException sdsd)
{
}
Error:
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
Any suggestions in this regard would helpful.
Without more information, my guess would be that the asp.net application is running under an account which does not have enough privs to access a network resource. You can try changing the account under which the asp.net application runs or impersonate a user with network access rights.

msxml3.dll error '80072ee2' in ASP Page

We have just moved to a new dedicated server that has Windows 2008 and SQL Server 2008. I am trying to access an ASP page on the same server using Server.CreateObject("MSXML2.ServerXMLHTTP").
On our previous 2003 server this worked correctly, however with the new 2008 server the operation just times out.
Here is the code:
strURL = "http://www.storeboard.com/profile/profile_view.asp?MemberID=" & MemberID & "&sid=" & cSession.SessionID
Set oXMLHttp = Server.CreateObject("MSXML2.ServerXMLHTTP")
oXMLHttp.open "GET", strURL, false
oXMLHttp.send()
IF oXMLHttp.status = 200 THEN
strOut = oXMLHttp.responseText
ELSE
strOut = "Could not get XML data."
END IF
Set oXMLHttp = nothing
The code is very simple but I get the following error:
msxml3.dll error '80072ee2'
The operation timed out
/handle404.asp, line 291
Line 291 refers to oXMLHttp.Send() line.
Is there an alternative code I can use? I use the script other places on the server that access files on other servers and they work correctly, but any access to files on our server doesn't work.
Is there an alternative method that will allow me to keep the URL intact in the browser? The person could write the URL in their browser: http://www.example.com/hello the file doesn't exist but I have a 404 handler that then points the user to the correct path without changing the browser URL which is essential for our SEO ratings.
Microsoft has a published a KB article entitled INFO: Do Not Send ServerXMLHTTP or WinHTTP Requests to the Same Server
If the ServerXMLHTTP or WinHTTP component must send a request to
another ASP on the same server, the target ASP must be located in a
different virtual directory and set to run in high isolation. Avoid
using ServerXMLHTTP or WinHTTP to send a request to an ASP that is
located in the same virtual directory.
...
A finite number of worker threads (in the Inetinfo.exe or Dllhost.exe
process) is available to execute ASP pages. If all of the ASP worker
threads send HTTP requests back to the same Inetinfo.exe or
Dllhost.exe process on the server from which the requests are sent,
the Inetinfo.exe or Dllhost.exe process may deadlock or stop
responding (hang), because the pool of worker threads to process the
incoming requests will be exhausted. This is by design.
As far as alternatives go, it depends on what you're doing with the response after you receive it. If the entire purpose of the script is to forward the request to profile_view.asp, you might be able to use Server.Transfer instead.
I had this same issue. In my case the web request I was trying to make was an internal site url (within the same app pool). With server side debugging set to enabled, the asp app pool seems to be restricted to a single worker thread. By disabling this feature, the request was then able to be processed.
msxml3.dll is pretty old. It was distributed with Internet Explorer 6 to give you a rough idea.
Can you have someone install a later version on the server?
http://support.microsoft.com/kb/269238 gives you a list of versions to send to whoever it responsible for the server.
If the problem is genuinely down to a time out you could look into switching ASP buffering off. (This based soley on a guess that if the server object started to receive a response it would hold off on the timeout front.
Alternatively you coudl try processing the value on the client side, below is a function from some code I wrote which does this....
function getDets(RateID) {
var xmlHttp;
try {
xmlHttp=new XMLHttpRequest(); // Firefox, Opera 8.0+, Safari
}
catch (e) {
try {
// Internet Explorer
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e) {
try {
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {
alert("Your browser does not support AJAX!");
return false;
}
}
}
xmlHttp.onreadystatechange=function()
{
if(xmlHttp.readyState==4) {
var str;
var newStr;
str=xmlHttp.responseText
newStr=str.split("|");
window.document.all.OR2.style.display="block";
window.document.all.OR3.style.display="block";
window.document.OvertimeRates.Description.value=newStr[0];
window.document.OvertimeRates.Factor.value=newStr[1];
}
}
if (RateID==0) {
window.document.OvertimeRates.Description.value="";
window.document.OvertimeRates.Factor.value="";
}
else {
xmlHttp.open("GET","GetOvertimeRate.asp?RateID="+RateID,true);
xmlHttp.send(null);
}
}
Good luck!

Resources