Asp.net MVC web site on iis goes idle after few minutes - asp.net

I have an asp.net mvc 5 site running on iis. In the Application_Start I have a call to this method called Run();.
private void Run()
{
Task t = new Task(() => new XyzServices().ProcessXyz());
t.Start();
t.ContinueWith((x) =>
{
Thread.Sleep(ConfigReader.CronReRunTimeInSeconds);
Run();
});
}
I am running a task which process some data, and as soon as the task completes I wait fr 20-30 seconds and rerun the task again.
Now all this works fine. But after a certain time, the process stops and its resumes only when I reopen the site url.
How do I overcome this ? Any ideas or suggestions ?

Might be your application pool is shutdown automatically
1) Open IIS.
2) Right click on your Application-Pool for the web application and select "Advanced Settings".
3) Set "Rapid-Fail Protection" -> "Enabled" to False.
If this is true, the Application pool is shut down if there are a specified number of worker process crashes within a specified time period. By default, an application pool is shutdown if there are 5 crashes within a 5 minutes interval.
for more info https://sharepoint.stackexchange.com/questions/22885/application-pool-is-auto-stopped-when-browse-web-application-in-iis7]

Related

IIS slow multithreading

We have a .NET application which is calling over OpenRia services on the server (IIS). This web service call is running a heavy calculation, where we are loading over LoadLibrary some DLL's, which we need to solve some linear systems. We need to go over a list of 1000 events. Every single event is a separate calculation and can be run independently from each other.
What we are doing is, that we create on a 64-core machine 60 tasks and every task is taking one event => run the calculation => take the next event => run the calculation and so on until the list is empty.
As soon the list is empty our calculation is finished.
We have now the strange behaviour that on the first run the calculation seems to run fast, but when we run the same calculation again it's getting slower on every run.
If we restart the server the calculation is running fast again.
We have done an analysis with PerfView and we have seen that on the second/third/fourth run the used threads from the IIS worker process are less than at the beginning.
On the first run the IIS worker process is using 60 threads (as we have defined) and on the second the process is using less than 60. On every run the actual threads used are less and less.
The first run the calculation needs around 3min. The second run we need 6min and the third run we are already around 15min.
What could be the problem? I have tried to use the ThreadPool, but I have the same effect as with the Tasks.
Here is some sample code:
//This part of code is called after the web service call
ConcurrentStack<int> events = new ConcurrentStack<int>();//This is a list of 1000 entries
ParallelOptions options = new ParallelOptions();
int interfacesDone = 0;
Task[] tasks = new Task[options.MaxDegreeOfParallelism];
for (int i = 0; i < options.MaxDegreeOfParallelism; i++)
{
tasks[i] = Task.Run(() =>
{
StartAnalysis(events);
});
}
Task.WaitAll(tasks);
private void StartAnalysis(ConcurrentStack<int> events)
{
while (!events.IsEmpty)
{
int index;
if (events.TryPop(out index))
{
DoHeavyCalculation();
}
}
}
ASP.NET processes requests by using threads from the .NET thread pool. The thread pool maintains a pool of threads that have already incurred the thread initialization costs.
Therefore, these threads are easy to reuse. The .NET thread pool is also self-tuning. It monitors CPU and other resource utilization, and it adds new threads or trims the thread pool size as needed.

ASP.NET Web API Startup Questions

I am creating an ASP.NET Web API using .NET 4.5.2. The API needs to connect to a runspace on startup. I have questions about when this Startup.Configuration method actually runs though. It does not seem to run when I start the website or app pool. It seems to wait until the first time somebody tries to access the website. Is this correct? Also, it seems to run again at random times. I have seen it run after 2 hours, 4 hours, and 16 hours. It doesn't really make any sense. Can somebody clear up for me when these methods should run? Also, if you have a suggestion for a better place to put them given that I want it to be a shared runspace for all connections and that I want it to run before anybody tries to connect to the API. Perhaps a separate service?
Also, would it be worth looking into ASP.NET CORE? I don't need it to run on anything other than IIS, however if there is a benefit to using CORE I am at a point where it will be easy to switch.
public partial class Startup
{
public Cache GlobalCache;
public static PowershellRunspace PSRunspace;
public static ActiveDirectory ADObjects = new ActiveDirectory();
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalCache = new Cache();
AppLog log = new AppLog();
log.InfoLog("Starting PowerShell Runspace in Hangfire...", true);
GlobalConfiguration.Configuration.UseSqlServerStorage("Hangfire");
BackgroundJob.Enqueue(() => log.InfoLog("Hangfire started!", true));
BackgroundJob.Enqueue(() => ADObjects.Startup(true));
BackgroundJob.Enqueue(() => StaticRunspace.Start());
app.UseHangfireDashboard();
app.UseHangfireServer();
}
}
Assuming you're running this application in IIS (and not self-hosting), the following rules apply:
The Configuration method runs once per application start.
The application is started lazily (on the first request to it via HTTP/S).
IIS has a few settings that affect the application:
An idle timeout. If the app isn't accessed via a request in 20 minutes then the application is unloaded / put offline. The next request starts it again.
A regular app pool recycle. It just straight up restarts the application by recycling the app pool every 1740 minutes.
So the behavior you're seeing is likely due to the infrequent access of the application, combined with the IIS defaults. If you'd like to see or configure the settings, you can do so by going into IIS, right clicking on your app pool, and selecting Advanced Settings.

how to avoid any timeout during a long running method execution

I am working on an asp.net mvc 5 web application , deployed inside IIS-8, and i have a method inside my application to perform a long running task which mainly scans our network for servers & VMs and update our database with the scan results. method execution might last between 30-40 minutes to complete on production environment. and i am using a schedule tool named Hangfire which will call this method 2 times a day.
here is the job definition inside the startup.cs file, which will call the method at 8:01 am & 8:01 pm:-
public void Configuration(IAppBuilder app)
{
var options = new SqlServerStorageOptions
{
PrepareSchemaIfNecessary = false
};
GlobalConfiguration.Configuration.UseSqlServerStorage("scanservice",options);
RecurringJob.AddOrUpdate(() => ss.Scan(), "01 8,20 ***");
}
and here is the method which is being called twice a day by the schedule tool:-
public void Scan()
{
Service ss = new Service();
ss.NetworkScan().Wait();
}
Finally the method which do the real scan is (i only provide a high level description of what the method will do):-
public async Task<ScanResult> NetworkScan()
{
// retrieve the server info from the DB
// loop over all servers & then execute some power shell commands to scan the network & retrieve the info for each server one by one...
// after the shell command completed for each server, i will update the related server info inside the DB
currently i did some tests on our test environment and every thing worked well ,, where the scan took around 25 seconds to scan 2 test servers.but now we are planning to move the application to production and we have around 120++ servers to scan. so i estimate the method execution to take around 30 -40 minutes to complete on the production environment. so my question is how i can make sure that this execution will never expire , and the ScanNetwork() method will complete till the end?
Instead of worrying about your task timing out, perhaps you could start a new task for each server. In this way each task will be very short lived, and any exceptions caused by scanning a single server will not effect all the others. Additionally, if your application is restarted in IIS any scans which were not yet completed will be resumed. With all scans happening in one sequential task this is not possible. You will likely also see the total time to complete a scan of your entire network plummet, as the majority of time would likely be spent waiting on remote servers.
public void Scan()
{
Service ss = new Service();
foreach (var server in ss.GetServers())
{
BackgroundJob.Enqueue<Service>(s => s.ServerScan(server));
}
}
Now your scheduled task will simply enqueue one new task for each server.

Throwing an Exception In a ASP.NET Thread To Bring Down IIS

I am doing a code review and found this piece of code. Does throwing an exception inside a thread bring down IIS? Read the comments.
Thread unhandledExceptionThread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate()
{
System.Threading.Thread.Sleep(90 * 1000);
throw new ApplicationException("Thread 1");
}));
unhandledExceptionThread.Name = "IntentionalCrasher";
Thread environmentExitThread = new System.Threading.Thread(new System.Threading.ThreadStart(delegate()
{
System.Threading.Thread.Sleep(100 * 1000);
Environment.Exit(-500);
}));
environmentExitThread.Name = "Thread 2";
unhandledExceptionThread.Start();
environmentExitThread.Start();
It won't bring "IIS down" but it will terminate the ASP.NET worker process. It will restart.
Your code snippet first tries to die by throwing an exception. 10sec later, if that didn't help, it takes matters into its own hands and kills the process.
Alternatively, it could call AppDomain.Unload on the current domain. But this is a reasonable way to restart the worker process.
Make sure rapid fail protection is disabled. This feature is the devil because it permanently shuts down your app after 5 failures. Permanently without notification. On any kind of error.

How do you force the IIS Application Pool to restart whenever the App Domain is reloaded?

We have an ASP.NET MVC 4 application that links to legacy native code. The problem is that this legacy code has global statics that are constructed at startup, but because native code knows nothing about App Domains, that code is not re-initialized when the App Domain is reloaded. This causes incorrect behaviour or crashes in our app until the Application Pool process is restarted.
Because of this, I would like to force the Application Pool to recycle whenever our application's App Domain is recycled. Is there a setting in IIS for this, or is there code that I can call in my application as the domain is being unloaded?
Some info on my setup,
ASP.NET MVC 4 application
IIS 7.5, but I can move to 8 if required
I can ensure that there is one application per Application Pool, so I will not be affecting other applications.
Update
Based on the answer below, I hooked up to the AppDomain unload event and used code similar to the following to recycle the Application Pool.
try
{
// Find the worker process running us and from that our AppPool
int pid = Process.GetCurrentProcess().Id;
var manager = new ServerManager();
WorkerProcess process = (from p in manager.WorkerProcesses where p.ProcessId == pid select p).FirstOrDefault();
// From the name, find the AppPool and recycle it
if ( process != null )
{
ApplicationPool pool = (from p in manager.ApplicationPools where p.Name == process.AppPoolName select p).FirstOrDefault();
if ( pool != null )
{
log.Info( "Recycling Application Pool " + pool.Name );
pool.Recycle();
}
}
}
catch ( NotImplementedException nie )
{
log.InfoException( "Server Management functions are not implemented. We are likely running under IIS Express. Shutting down server.", nie );
Environment.Exit( 0 );
}
A more brutal approach is to call Process.GetCurrentProcess().Kill()
Not very graceful, but if your site has its own app pool and you don't care any current requests being brutally stopped, that's quite effective!
A simplified VB version of the code you shared. This version uses a For loop instead of a LINQ query. Also, in order to use Microsoft.Web.Administration, you must import the DLL from c:\windows\system32\inetsrv
Imports System.Diagnostics
Imports Microsoft.Web.Administration
Dim pid As Integer = Process.GetCurrentProcess().Id
Dim manager = New ServerManager()
For Each p As WorkerProcess In manager.WorkerProcesses
If p.ProcessId = pid Then
For Each a As ApplicationPool In manager.ApplicationPools
If a.Name = p.AppPoolName Then
a.Recycle()
Exit For
End If
Next
Exit For
End If
Next
Based on your post it appears you know when you want to trigger the restart so here is a Restarting (Recycling) an Application Pool post that will tell you how.

Resources