I use the following code in a asp.net website.
On application init i call InitializeTimer() once.
The goal of the code was to run DoWork() once every hour (1 time per hour) .
I also wanted the code to execute on different time every loop so i added the random part.
The result i got was werid , i can not find a explaination why is happens.
The code executed the function after 2hrs , then again after 2hrs , then after 3hrs , then after 2hrs , and 2hrs again.****
Can anybody explain the reason?
using System.Timers;
....
private static random = new Random();
....
public static void InitializeTimer()
{
tTimer = new Timer();
tTimer.AutoReset = true;
tTimer.Interval = TimeSpan.FromHours(1.0).TotalMilliseconds;
tTimer.Elapsed += new ElapsedEventHandler(ClassName1.tMailer_Elapsed);
tTimer.Start();
}
private static void tTimer_Elapsed(object sender, ElapsedEventArgs e)
{
tTimer.Interval += random.Next(-5, 5);
DoWork();
}
Update:
Please don't post "use windows service" , or "scheduled task".
My question is for the following code I'm not looking for better alternatives.
Also , during this test (10hrs) , website was with high traffic , iis pool did not restart!
Based on the following MSDN: (http://msdn.microsoft.com/en-us/library/system.timers.timer.interval.aspx)
If the interval is set after the Timer
has started, the count is reset. For
example, if you set the interval to 5
seconds and then set the Enabled
property to true, the count starts at
the time Enabled is set. If you reset
the interval to 10 seconds when count
is 3 seconds, the Elapsed event is
raised for the first time 13 seconds
after Enabled was set to true.
Is it possible that re-setting the interval in the elapsed function is the cause of the problem?
Meaning that when tTimer_Elapsed function is called the count is 1hr(min a few millisecond)
and my code "tTimer.Interval += random.Next(-5, 5);" is adding another full hour to the Interval?
ASP.NET applications will get shut down when not in use. If someone hits your site, and then no more hits, it can get shut down. Your timer won't fire.
For this type of maintenance work you want to use a windows scheduled task or windows service.
Check this out... Jeff Atwood actually discussed something similar. I guess it worked, but according to Jeff the site outgrew this method so they went to a dedicated task.
Since .net 4.5.2, there is a class called HostingEnvironment, it can do what you're asking, here is how to use:
https://blog.mariusschulz.com/2014/05/07/scheduling-background-jobs-from-an-asp-net-application-in-net-4-5-2
The HostingEnvironment.QueueBackgroundWorkItem method lets you
schedule small background work items. ASP.NET tracks these items and
prevents IIS from abruptly terminating the worker process until all
background work items have completed.
I second Sams suggestion of using windows scheduled task to hit a page every hour. I tried and tried to get mine to work and it sort of worked. I went to a scheduled task and it has never failed.
Related
I have a method that detects beacons after each 30 seconds. The scenario is as follows:
The scan period of beacons is 60 seconds.
The waiting period before the next scan is 30 seconds.
The above settings have already been defined in the BeaconDectector class. Now to display the beacons scanned on my UI, I have the following:
private void Button_Clicked(object sender, EventArgs e)
{
bool start = true;
while (start) {
beaconsFound = StartDetection();
Device.BeginInvokeOnMainThread(() =>
{
listView.ItemsSource = beaconsFound;
});
}
}
The StartDetection contains the logic that take place every 30 seconds and the scan period is 60 seconds. How can I ensure that I don't miss any beacons to get displayed on my listview?
Please advise. Thank you.
You should definitely not use active waiting while(start) to manage this. A better solution would be a Timer. You can see the basics for this in this blogpost.
Furthermore, ensure you are not running any long running code on the UI thread (which is what Button_Clicked runs on). Ideally, your timer should fire each 30 seconds, start a new Task for the detection and use Device.BeginInvokeOnMainThread to update the list when appropriate.
Here I below pasted code I'm using in current window service solution, this will run job every day 10 AM regularly, I will pass the parameters using App.configuaration file
APP.CONFIG
<add key ="FIREHOST_TIME" value ="10" ></add>
<add key ="SETDAYS" value ="1" ></add>
CODE BEHIND PAGE
protected override void OnStart(string[] args)
{
DateTime tenAM = DateTime.Today.AddHours(FIREHOST_TIME);
if (DateTime.Now > tenAM)
tenAM = tenAM.AddDays(SETDAYS);
// calculate milliseconds until the next 10:00 AM.
int timeToFirstExecution = (int)tenAM.Subtract(DateTime.Now).TotalMilliseconds;
// calculate the number of milliseconds in 24 hours.
int timeBetweenCalls = (int)new TimeSpan(24, 0, 0).TotalMilliseconds;
TimerCallback methodToExecute = kickstart;
// start the timer. The timer will execute "ProcessFile" when the number of seconds between now and
// the next 10:00 AM elapse. After that, it will execute every 24 hours.
System.Threading.Timer timer = new System.Threading.Timer(methodToExecute, null, timeToFirstExecution, timeBetweenCalls);
}
Now I am trying to run my service, based up on the below Mentioned conditions:
I want to start my service but it should job perform the job based on the this new tag which I will add newly in app.config
BY based on above four tags
if RUN_NOW == 1
has to perform service based on FIREHOST_TIME and SETDAYS normal thing
else
service have to perform the Job doing by after 5 days(because WAIT_DAYS = 5)
then it have to use the FIREHOST_TIME and SETDAYS value
Note: service should not get stopped, it should be in started condition only
How can I achieve this?
I don't know exactly how you want implement the whole program logic, the portion I can try to help you is about reacting to a config file modification without restarting the service, this can be done with:
ConfigurationManager.RefreshSection("thesectiontorefresh");
for a better work, you can call this with a FileSystemWatcher listening for someone modifying the app.config file and react properly after calling the refresh as show above. You can obtain the configuration file path with this:
AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
As a general information, consider to redesign the way you are solving the problem by using system scheduled task instead of writing your own service.
My application could have up to roughly 100 requests for a batch job within a few milliseconds but in actuality, these job requests are being masked as one job request.
To fix this issue so that only one job request is just not feasible at the moment.
A workaround that I have thought is to program my application to fulfill only 1 batch job every x milliseconds, in this case I was thinking of 200 milliseconds, and ignore any other batch job that may come in within those 200 milliseconds or when my batch job have completed. After those 200 milliseconds are up or when the batch job is completed, my application will wait and accept 1 job request from that time on and it will not process any requests that may have been ignored before. Once my application accepts another job requests, it will repeat the cycle above.
What's the best way of doing this using .Net 4.0? Are there any boiler plate code that I can simply follow as a guide?
Update
Sorry for being unclear. I have added more details about my scenario. Also I just realized that my proposed workaround above will not work. Sorry guys, lol. Here's some background information.
I have an application that builds an index using files in a specified directory. When a file is added, deleted or modified in this directory, my application listens for these events using a FileSystemWatcher and re-indexes these files. The problem is that around 100 files can be added, deleted or modified by an external process and they occur very quickly, ie: within a few milliseconds. My end goal is to re-index these files after the last file change have occurred by the external process. The best solution is to modify the external process to signal my application when it has finished modifying the files I'm listening to but that's not feasible at the moment. Thus, I have to create a workaround.
A workaround that may solve my problem is to wait for the first file change. When the first file change have occurred, wait 200 milliseconds for any other subsequent file changes. Why 200 milliseconds? Because I'm hoping and confident that the external process can perform its file changes within 200 milliseconds. Once my application have waited for 200 milliseconds, I would like it to start a task that will re-index the files and go through another cycle of listening to a file change.
What's the best way of doing this?
Again, sorry for the confusion.
This question is a bit too high level to guess at.
My guess is your application is run as a service, you have your requests come into your application and arrive in a queue to be processed. And every 200 ms, you wake the queue and pop and item off for processing.
I'm confused about the "masked as one job request". Since you mentioned you will "ignore any other batch job", my guess is you haven't arranged your code to accept the incoming requests in a queue.
Regardless, you will generally always have one application process running (your service) and if you choose you could spawn a new thread for each item you process in the queue. You can monitor how much cpu/memory utilization this required and adjust the firing time (200ms) accordingly.
I may not be accurately understanding the problem, but my recommendation is to use the singleton pattern to work around this issue.
With the singleton approach, you can implement a lock on an object (the access method could potentially be something along the lines of BatchProcessor::GetBatchResults) that would then lock all requests to the batch job results object. Once the batch has finished, the lock will be released, and the underlying object, will have the results of the batch job available.
Please keep in mind that this is a "work around". There may be a better solution that involves looking into and changing the underlying business logic that causes multiple requests to come in for a job that's processing on demand.
Update:
Here is a link for information regarding Singleton (includes code examples): http://msdn.microsoft.com/en-us/library/ff650316.aspx
It is my understanding that the poster has some sort of an application that sits and waits for incoming requests to perform a batch job. The problem that he is receiving multiple requests within a short period of time that should actually have come in as just a single request. And, unfortunately, he is not able to solve this problem.
So, his solution is to assume that all requests received within a 200 ms timespan are the same, and to only process these once. My concern with this would be whether this assumption is correct or not? This entirely depends on the sending systems and the environment in which this is being used. The general idea to be able to do this would be to update a lastReceived date/time when a request is processed. Then when a new request comes in, compare the current date/time to the lastReceived date/time and only process it if the difference is greater than 200 ms.
Other possible solutions:
You said you could not modify the sending application so only one job request was sent, but could you add additional information to it, for instance a unique identifier?
Could you store the parameters from the last job request and compare it with the next job request and only process them if they are different?
Based on your Update
Here is an example how you could wait 200ms using a Timer:
static Timer timer;
static int waitTime = 200; //in ms
static void Main(string[] args)
{
FileSystemWatcher fsw = new FileSystemWatcher();
fsw.Path = #"C:\temp\";
fsw.Created += new FileSystemEventHandler(fsw_Created);
fsw.EnableRaisingEvents = true;
Console.ReadLine();
}
static void fsw_Created(object sender, FileSystemEventArgs e)
{
DateTime currTime = DateTime.Now;
if (timer == null)
{
Console.WriteLine("Started # " + currTime);
timer = new Timer();
timer.Interval = waitTime;
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
else
{
Console.WriteLine("Ignored # " + currTime);
}
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
//Start task here
Console.WriteLine("Elapsed # " + DateTime.Now);
timer = null;
}
I use Asp .NET Mvc 3 for creating web page and I need to change something in database after each 20 minutes...
I set Timer in my Global.asax.cs file . Here is the code
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
Unit = new UnitOfWork();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1200000; //20 minutes
timer.Elapsed += new System.Timers.ElapsedEventHandler(Elapsed);
timer.Start();
}
void Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Unit.Srvc.UpdateUserActivity();
}
Now I run it today, and what a pitty, it works only one time... After 20 minutes it change database and it's all.
P.S.Yesteday I tested it in 20 seconds and it works fine. But,today it don't want to work correctly in 20 minutes interval. Thank you for help.
P.S.2 I used Stored Procedure for updating database.
P.S.3 Just now I detect that it works randomly :D In 5:32Am I run the program... It works in 5:52Am, doesn't work in 6:12Am, and works now(now is 6:49 Am, I don't know when it works).
Most likely cause is that your AppDomain is shutting down due to inactivity, which means the entire application is not running. The idle timeout is 20 minutes of inactivity, I think.
See this question:
How to keep ASP.NET assemblies in AppDomain alive?
To me it looks like your timer will be killed by garbage collection as you are not keeping a reference to it after it goes out of scope from Application_Start. Try adding:
Application["Whatever"] = timer;
You might be finding that your thread (from the IIS AppPool) is being recycled or shut down.
Web applications typically work best when used for request-response processing rather than this type of behaviour. It's not clear what you are up to, but assuming you are using SQL Server perhaps you could look at maintenance tasks or triggers if it involves denormalizing data (i.e. rolling up calculated data). If it involves data collected during the request-response process then perhaps you might look at using the web cache and some cache expiration operations for the delayed persistence.
My guess is too that the session simply expires but I would like to add a little extra.
Reading the code I guess (again) that you are marking the user in the database as 'not active' or disconnected or something like that. If so, do not use a timer to do this, instead, set the session expiration (when the user hasn't sent any requests for a certain period) to the required duration and put the code you want to run when that happens in the Session_OnEnd handler
I have a windows service written in c#. It has a timer inside, which fires some functions on a regular basis. So the skeleton of my service:
public partial class ArchiveService : ServiceBase
{
Timer tickTack;
int interval = 10;
...
protected override void OnStart(string[] args)
{
tickTack = new Timer(1000 * interval);
tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
tickTack.Start();
}
protected override void OnStop()
{
tickTack.Stop();
}
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
...
}
}
It works for some time (like 10-15 days) then it stops. I mean the service shows as running, but it does not do anything. I make some logging and the problem can be the timer, because after the interval it does not call the tickTack_Elapsed function.
I was thinking about rewrite it without a timer, using an endless loop, which stops the processing for the amount of time I set up. This is also not an elegant solution and I think it can have some side effects regarding memory.
The Timer is used from the System.Timers namespace, the environment is Windows 2003. I used this approach in two different services on different servers, but both is producing this behavior (this is why I thought that it is somehow connected to my code or the framework itself).
Does somebody experienced this behavior? What can be wrong?
Edit:
I edited both services. One got a nice try-catch everywhere and more logging. The second got a timer-recreation on a regular basis. None of them stopped since them, so if this situation remains for another week, I will close this question. Thank you for everyone so far.
Edit:
I close this question because nothing happened. I mean I made some changes, but those changes are not really relevant in this matter and both services are running without any problem since then. Please mark it as "Closed for not relevant anymore".
unhandled exceptions in timers are swallowed, and they silently kill the timer
wrap the body of your timer code in a try-catch block
I have seen this before with both timer, and looped services. Usually the case is that an exception is caught that stops the timer or looping thread, but does not restart it as part of the exception recovery.
To your other points...
I dont think that there is anything "elegant" about the timer. For me its more straight forward to see a looping operation in code than timer methods. But Elegance is subjective.
Memory issue? Not if you write it properly. Maybe a processor burden if your Thread.Sleep() isn't set right.
http://support.microsoft.com/kb/842793
This is a known bug that has resurfaced in the Framework more than once.
The best known work-around: don't use timers. I've rendered this bug ineffective by doing a silly "while (true)" loop.
Your mileage may vary, so verify with your combination of OS/Framework bits.
Like many respondents have pointed out exceptions are swallowed by timer. In my windows services I use System.Threading.Timer. It has Change(...) method which allows you to start/stop that timer. Possible place for exception could be reentrancy problem - in case when tickTack_Elapsed executes longer than timer period. Usually I write timer loop like this:
void TimeLoop(object arg)
{
stopTimer();
//Do some stuff
startTimer();
}
You could also lock(...) your main loop to protect against reentrancy.
Interesting issue. If it is truly just time related (i.e. not an exception), then I wonder if you can simply periodically recycle the timer - i.e.
private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
CheckForRecycle();
// ... actual code
}
private void CheckForRecycle()
{
lock(someLock) {
if(++tickCount > MAX_TICKS) {
tickCount = 0;
tickTack.Stop();
// re-create timer
tickTack = new Timer(...);
tickTack.Elapsed += ...
tickTack.Start();
}
}
}
You could probably merge chunks of this with the OnStart / OnStop etc to reduce duplication.
Have you checked the error logs? Maybe you run out of timers somehow. Maybe you can create just one timer when you initialize the ArchiveService and skip the OnStart stuff.
I have made exactly the same as you in a few projects but have not had the problem.
Do you have code in the tickTac_Elapsed that can be causing this? Like a loop that never ends or some error that stops the timer, using threads and waiting for ending of those and so on?