Hello I am make a long running service class that runs diffidently but it's thread is paused all the time except for once a day when it has to check some data for my asp.net website. It is a WCF file in an asp.net website. The class inherits from this interface :
[ServiceContract]
public interface IService
{
[OperationContract]
void DoWork();
}.
This is the code it uses for creating the thread the class run on :
//Initialize the thread
Thread = new Thread(new ThreadStart(threadDoSomething));
//The thread is a background thread; it is a long running service
Thread.IsBackground = true;
//This Thread does not need much CPU attention so it is not a high priority
Thread.Priority = ThreadPriority.Lowest;
//Run the tread
Thread.Start(this);
I have heard that IIS will occasionally stop long running processes to save memory, will it stop this process?
Yes, IIS will recycle ApplicationPools when no activity has been received in a period (it's configurable).
A simple trick to avoid this is to do that thread navigate a page on your web application to avoid it but it will finally sometime recycle it after a long period.
UPDATE:
Ehm... if your app is a windows service then IIS has nothing to do with your thread...
Related
I have a .NET MVC web app which requires time to be properly shutdown and so whenever the IIS app domain is recycled (i.e. a new instance is spun up and receives all new requests while the old instance shuts down waiting for outstanding requests to complete) I need to block this app shutdown until my app's current async background work (containing no outstanding requests) has completed. IRegisteredObject (see http://blog.stephencleary.com/2014/06/fire-and-forget-on-asp-net.html) offers this blocking ability, though, my processes always seem to die at times inconsistent with my blockage time and IIS settings.
I saw this post (IRegisteredObject not working as expected) which explained the importance of the IIS Shutdown Time Limit but, while IRegisteredObject seems to block for a period of time, I cannot get the recycle to block for the desired time of 2 hours (nor can I generally get results which make sense based off various settings).
Below is a simple implementation of IRegisteredObject with a background thread that I've been using for tests:
public class MyRegisteredObject : IRegisteredObject
{
public void Register()
{
HostingEnvironment.RegisterObject(this);
Logger.Log("Object has been registered");
}
// the IRegisteredObject.Stop(...) function gets called on app domain recycle.
// first, it calls with immediate:false, indicating to shutdown work, then it
// calls 30s later with immediate:true, and this call 'should' block recycling
public void Stop(bool immediate)
{
Logger.Log("App domain stop has been called: "
+ (immediate ? "Immediate" : "Not Immediate")
+ " Reason: " + HostingEnvironment.ShutdownReason);
if (immediate)
{
// block for a super long time
Thread.Sleep(TimeSpan.FromDays(1));
Logger.Log("App domain immediate stop finished");
}
}
// async background task to track if our process is still alive
public async Task RunInBackgroundAsync()
{
Logger.Log("Background task started");
var timeIncrement = TimeSpan.FromSeconds(5);
var time = TimeSpan.Zero;
while (time < TimeSpan.FromDays(1))
{
await Task.Delay(timeIncrement).ConfigureAwait(false);
time += timeIncrement;
Logger.Log("Background task running... ("
+ time.ToString(#"hh\:mm\:ss") + ")");
}
Logger.Log("Background task finished");
}
}
public static class Logger
{
private static readonly string OutputFilename = #"C:\TestLogs\OutputLog-" + Guid.NewGuid() + ".log";
public static void Log(string line)
{
lock (typeof(Logger))
{
using (var writer = new StreamWriter(OutputFilename, append: true))
{
writer.WriteLine(DateTime.Now + " - " + line);
writer.Close();
}
}
}
}
In app start, I start the IRegisteredObject component:
var recycleBlocker = new MyRegisteredObject();
recycleBlocker.Register();
var backgroundTask = recycleBlocker.RunInBackgroundAsync();
Finally, when testing, I have sparked app domain recycles through 3 separate means:
(1) Web.config file change (yields a HostingEnvironment.ShutdownReason value of ConfigurationChange)
(2) Manual recycle through clicking the app's Application Pool and then Recycle in IIS Manager (yields a HostingEnvironment.ShutdownReason value of HostingEnvironment)
(3) Allowing the app to automatically recycle based off of the IIS setting under Process Model - "Idle Time-out (minutes)" (also yields a HostingEnvironment.ShutdownReason value of HostingEnvironment)
I would not have expected this, but the manner in which the recycle is triggered seems to play a drastic role... below are my findings through tests where I modified the means of recycle and IIS settings (Shutdown limit and Idle time-out).
Findings:
---- Web.config change recycle (ShutdownReason: ConfigurationChange) ----
After the IRegisteredObject(immediate: true) call occurs, I see in my logs that the background task lasts almost exactly the time set for IIS Idle Time-out, while Shutdown Time Limit plays no role whatsoever. Further, with this recycle, assuming I set the Idle time-out high enough, the recycle blocking is always respected. I blocked for a full day in one test by setting the Idle time-out to 0 (i.e. off).
---- IIS Manager manual recycle (ShutdownReason: HostingEnvironment) ----
After the IRegisteredObject(immediate: true) call occurs, the logs show the exact opposite behavior compared to Web.config change. No matter what the Idle Time-out is, the blockage seems unaffected. Conversely, the Shutdown Time Limit dictates how long to block the recycle (up to a point). From 1 second up through 5 minutes, the recycle will be blocked based on this Shutdown Limit. However, if the setting is set higher or turned off, blockage seems to remain at the ceiling of around 5 minutes.
---- Idle time-out automatic recycle (ShutdownReason: HostingEnvironment) ----
Finally something predictable... the automatic recycle does actually get triggered based on the Idle Time-out setting, which then causes a situation similar to the Manual Recycle case: Shutdown Time Limit respected up to about 5 minutes but no longer than that. Presumably this is because the automatic and manual recycles each have the same HostingEnvironment.ShutdownReason: HostingEnvironment.
Ok... I apologize for the length of this! As you can see, the combination of recycle methods and IIS settings simply do not seem to yield expected results. Further, my goal of this all is to be able to block for a max of two hours, which does not seem possible from my tests outside of the web.config recycle case, no matter the settings I choose.... Can someone please shed light onto what exactly is going on under the hood here? What role does ShutdownReason play? What role do these IIS settings play?
Fundamentally, what am I missing here, and how can I use IRegisteredObject to block for longer periods of time caused from automatic recycles??
There are two different concepts in play here-
Application domain
Application pool
Application domains provide an isolation boundary for security, reliability, and versioning, and for unloading assemblies. Application pools define a set of Web applications that share one or more worker processes. Each application pool could be hosting one or more application domains.
Application pool can be recycled in the following ways
Triggering IIS Manager manual recycle
Invoking IIS reset from command prompt
Setting idle timeout or shutdown time limit on your Application pool
Application domain is recylced when you touch the Web.config, Global.asax or any dll in the bin folder of an application.
IRegisteredObject is able to intercept the process of application domain unloading, however, it does not have any control over the application pool recycle. When application pool recycle is triggered, it kills and restarts the w3wp.exe process and ends up killing all the application domains associated with the application pool.
This should explain why your IRegisteredObject was working as expected when you touched your Web.config but would not perform the expected actions when you recylced the application pool. If your idle-timeout or shut down timeout are less than the time window that your IRegisteredObject keeps the application domain alive, after a Application domain recycle is triggered, the IRegisteredObject will try to keep the application domain alive but when the idle-timeout or the shut-down timeout is reached, the application pool will recycle and application domain will be killed regardless of the IRegisteredObject.
A solution to your problem will be to turn the idle timeout and shut down time limit settings off for the application pool and rely on some alternate method to recycle your application pool. In that case, your application pool will not be recycled automatically and you can rely on your IRegisteredObject to keep the application domain alive.
I am using the ApplicationPool class's ApplicationPool.Stop method to stop the app pool via C# code. This method stops the app pool, it is fine. But the issue is that I want to detect when the pool has stopped since that method takes some time to make the app pool in stopped state. Is there any event which I should wire to detect whether the app pool has stopped?
Edit: I can't use Global.asax (of site of which I am stopping the app pool) since I am stopping the app pool from another application.
You can SpinWait until your application pool is stopped. Something like this:
ApplicationPool pool = //your pool here.
pool.Stop();
if (SpinWait.SpinUntil(() => pool.State == ObjectState.Stopped, TimeSpan.FromSeconds(30)))
{
//The application pool has stopped
}
else
{
//The application pool did not stop within 30 seconds.
//An error probably occured.
}
You don't have to specify a timeout, however I would strongly recommend it. If you don't, you risk completely blocking the rest of your process.
My application is a asp.net web service. There is a one more windows service ruining in the same server and trigger the web-service by specified intervals.
So in each web-service call, in side the web server, it create a new thread and start to do the task that web service suppose to do.
Some times, this started thread could not finish the assigned task, before next web service call comes. So the next web-service call create a same kind of a new thread and assign new task to the new thread.
So if I check the server in busy situations, Sometime there are 20+ parallel threads ruining.
Every thing works fine. But server (windows 2003 sp2) looks not responding some times. So I check the CPU performance in the Task Manager and it shows 100% when the web-service start to work. even if there are only 1,2 threads same thing happens.
I feel something wrong. Am i doing something conceptually wrong. Appreciate some advice.
Edit
public class EmailPrinter : System.Web.Services.WebService
public void webServiceMethod()
{
Thread email_thread = new Thread(new ThreadStart(this.downloadEmails));
email_thread.Start();
}
private void downloadEmails(object sender, DoWorkEventArgs e)
{
EmailService.init();
EmailService.ReceiveEmail();
}
}
I have a Windows service which performs a fairly long running task. At the moment, I spawn a new thread, which executes a method which goes off and calls this windows service. This code looks like:
Thread thread = new Thread(new ThreadStart(ExecyuteLongRunningMethod));
thread.Start();
thread.Join();
Higher up in the callstack (when this code is done), a message box popups stating the result of the operation.
However, while this block of code executes (ExecuteLongRunningMethod calls the windows svc), a message box popups stating that nothing has changed as a result of the operation, but because this is before the code block above has completed, the wrong message box appears.
Thus, the question is, what would be the proper way to only continue execution in the winforms app (this is what calls the windows svc), ONLY when the windows service is finished? I am thinking that the approach above is incorrect as the thread will call the windows service (another process), so while the windows service does its stuff, my code (winforms app) will continue. Either some sort of signaling is required, or something like named pipes?
The app is in .NET 3.5.
Thanks
Expose the status of your service execution via a WCF API and call it using netTcp or named pipes, you could poll the service or use a WCF CallBack.
Why don't you use a BackgroundWorker, so you can set an event for its completion?
In Backgroundworker running method you can run the service and wait for a manual reset event (for example) or a mutex and, when received this you can exit main method.
So OnCompleted event is raised in your main thread (UI for example) and the job is done...
In your app add a Backgroundworker and name it bgw.
Then you can do:
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
// 1. Run the service
// 2. Wait for mutex
}
private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Here you can handle the end of the service
// and return the status in main thread
}
I have a console application that starts up, hosts a bunch of services (long-running startup), and then waits for clients to call into it. I have integration tests that start this console application and make "client" calls. How do I wait for the console application to complete its startup before making the client calls?
I want to avoid doing Thread.Sleep(int) because that's dependent on the startup time (which may change) and I waste time if the startup is faster.
Process.WaitForInputIdle works only on applications with a UI (and I confirmed that it does throw an exception in this case).
I'm open to awkward solutions like, have the console application write a temp file when it's ready.
One option would be to create a named EventWaitHandle. This creates a synchronization object that you can use across processes. Then you have your 'client' applications wait until the event is signalled before proceeding. Once the main console application has completed the startup it can signal the event.
http://msdn.microsoft.com/en-us/library/41acw8ct(VS.80).aspx
As an example, your "Server" console application might have the following. This is not compiled so it is just a starting point :)
using System.Threading;
static EventWaitHandle _startedEvent;
static void main()
{
_startedEvent = new EventWaitHandle(false, EventResetMode.ManualReset, #"Global\ConServerStarted");
DoLongRunnningInitialization();
// Signal the event so that all the waiting clients can proceed
_startedEvent.Set();
}
The clients would then be doing something like this
using System.Threading;
static void main()
{
EventWaitHandle startedEvent = new EventWaitHandle(false, EventResetMode.ManualReset, #"Global\ConServerStarted");
// Wait for the event to be signaled, if it is already signalled then this will fall throught immediately.
startedEvent.WaitOne();
// ... continue communicating with the server console app now ...
}
What about setting a mutex, and removing it once start up is done. Have the client app wait until it can grab the mutex before it starts doing things.
Include an is ready check in the app's client interface, or have it return a not ready error if called before it's ready.
Create a WCF service that you can use for querying the status of the server process. Only start this service if a particular command is passed on the command line. The following traits will ensure a very fast startup of this service:
Host this service as the first operation of the client application
Use the net.tcp or net.pipe binding because they start very quickly
Keep this service as simple as possible to ensure that as long as the console application doesn't terminate, it will remain available
The test runner can attempt to connect to this service. Retry the attempt if it fails until the console application terminates or a reasonably short timeout period expires. As long as the console application doesn't terminate unexpectedly you can rely on this service to provide any additional information before starting your tests in a reasonably short period of time.
Since the two(the console application, and integration test app that makes client calls - as I understand) are separate application, so there should be a mechanism - a bridge - that would tell play as a mediator(socket, external file, registry, etc).
Another possibility could be that you come up with an average time the console takes to load the services and use that time in your test app; well, just thinking out loud!