My service will run daily tasks at multiple times. Here is my service code:
private DateTime m_scheduleTime;
private List<Task> m_tasksList; // Task includes id and time ("23:00")
protected override void OnStart(string[] args) {
SetSchedule();
}
private void SetSchedule()
{
Timer[] timers = new Timer[m_tasksList.Count];
int iHours = 0; int iMinutes = 0;
for (int i = 0; i < timers.Length; i++)
{
iHours = Int16.Parse(m_tasksList[i].Time.Split(':')[0]);
iMinutes = Int16.Parse(m_tasksList[i].Time.Split(':')[1]);
m_scheduleTime = DateTime.Today.AddDays(1).AddHours(iHours).AddMinutes(iMinutes);
timers[i] = new Timer();
timers[i].Enabled = true;
timers[i].Interval = m_scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
timers[i].Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
}
protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
DoWork(int taskId);
}
The code above is not tested, I built it from relevant code samples. So my problems are I don't know whether I am on the right track and if I'm right, I don't know which timer fires the _Elapsed event so that I can pass respective parameter. Any better solution would be appreciated!
You'd likely have better results using a single System.Threading.Timer that expires periodically at some minimum resolution, say every 60 seconds.
When your service starts, calculate the next scheduled run time for all of your tasks, inserting them into a priority queue as you go. The priority queue should be ordered by the scheduled run time.
Each time your timer expires, evaluate the scheduled run time of the task at the head of your queue. If the task's run time has been reached, pop it from the queue and push it to queue where it will be executed by your worker threads. Repeat this process until you either run out of tasks in the queue or find a task that is not yet ready to run.
Once a task has completed, calculate it's next scheduled run time and insert it into the scheduled priority queue.
If your service is purely for the purpose of running these scheduled tasks, I would suggest that you consider using the Windows Task Scheduler instead. Honestly, even if your service provides other functionality, using the Windows Task Scheduler to run periodic tasks will still be a better option than trying to roll your own scheduler.
You can find a managed wrapper for the Windows Task Scheduler, here http://taskscheduler.codeplex.com/. I have no knowledge of this wrapper, I found it referenced in this question: C# API for Task Scheduler 2.0.
Related
I notice the timer is not correct.
This is a very simple C# code: it will print current date/time every 1 minute.
My expected result is: let it run at 3:30 PM then we will have: 3:31 PM, 3:32 PM, 3:33 PM, ...
But sometime don't receive above result: sometime it is 3:31 PM, 3:32 PM, 3:34 PM, ...
So it lost 1 row.
Could anyone point me what is problem?
class Program
{
static Timer m_Timer;
static int countDown;
static void Main(string[] args)
{
countDown = 60;
m_Timer = new Timer(TimerCallback, null, 0, 1000);
while (true) { System.Threading.Thread.Sleep(10); };
}
static void TimerCallback(Object o)
{
countDown -= 1;
if (countDown <= 0)
{
Console.WriteLine(" ===>>>>>" + System.DateTime.Now.ToString());
countDown = 60;
}
System.Threading.Thread.Sleep(10000); //long running code demo
}
}
System.Threading.Timer runs on threads from thread pool. You run callback function which runs on one thread in pool every 1s and block it for 10s using sleep. Depending on how many threads you have in thread pool at some timepoints they all may be blocked and wait or .NET should allocate new thread up to the maximum of threads in pool for you.
From comments extended answer.
Each function is independent and it does not wait until another processing finish. A simple task is: call a function to do something every 1 minutes. "do something" in my case is saving local variables into SQL server. This process is fast not slow. I use 1 timer for many functions because each function is schedule in different cycle. For example, function 1 is triggered every 1 minute, function 2 is triggered every 10 seconds ... That why I use the timer 1 second.
Your use case seems to be more complex as I read it from initial question. You have different tasks and try to implement sort of scheduler. Maybe each particular tasks is fast but all together some runs may be longer and blocking. Not sure how this logic was well implemented but there could be a lot of edge cases e.g. some run was missed etc.
How I would approach it?
I would not try to implement on my own if scheduler can be more complex. I would pick ready solution, e.g. Quartz.NET. They consider edge cases and help to scale on cluster with needed and help with config.
In any case I would refactor bigger schedule to have each task to run on its schedule based on configuration (custom implementation or Quartz) as smaller tasks
I would scale your "queue" of tasks first locally by introducing some queue, for example using ConcurrentQueue or BlockingCollection or any produce-consumer to limit number of threads and if performance of such execution is not good scale on cluster. By doing so you can at least guarantee that N tasks can be scheduled and executed locally and everything beyond is queued. Maybe having some priorities for tasks can also help because there might be execution which could be missed but there are execution which must run on schedule.
I doubt it is a good idea to start from thread timer execution other threads or tasks if most likely you already have problems with threading.
You problem is not with System.Threading.Timer, it does its job well. Your use case is more complex.
Windows - is not real time operating system. So, if you expect that timer waits ecactly 1 second - it's wrong. There are many reasonsm when timer can wait more time. Because of timer resolution or other high load operations.
If you like newer .NET TPL syntax yo can write it like this:
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
internal class Program
{
private static void Main(string[] args)
{
Repeat(TimeSpan.FromSeconds(10));
Console.ReadKey();
}
private static void Repeat(TimeSpan period)
{
Task.Delay(period)
.ContinueWith(
t =>
{
//Do your staff here
Console.WriteLine($"Time:{DateTime.Now}");
Repeat(period);
});
}
}
}
The above code causes, that every second you run 10-second "demo" (sleep). You will run 10 worker threads simultanously.
Are you sure, this is what you are trying to achieve?
To see what really happens in your app, simply add:
Console.WriteLine($"Time:{DateTime.Now.ToString("hh:mm:ss.fff tt")},Thread:{Thread.CurrentThread.ManagedThreadId},countDown:{countDown}");
in the beginning of TimerCallback. You will notice, that timespan between following callbacks are not exactly 1000ms (usually it is a little bit more). This is perfectly normal in non-rtc OS, and, in most cases - it's not a problem. Just keep in mind, that Timer is not exact.
Moreover, if you are trying to use Timer that way, and trying to count ticks - these little errors cumulates in following ticks.
I just post what found here for people that have problem like me.
I found the answer from another thread.
I use "HighResolutionTimer.cs" and it works perfect:
https://gist.github.com/DraTeots/436019368d32007284f8a12f1ba0f545
Register a background task:
string myTaskName = "Task";
foreach (var cur in BackgroundTaskRegistration.AllTasks)
if (cur.Value.Name == myTaskName)
{
return;
}
await BackgroundExecutionManager.RequestAccessAsync();
BackgroundTaskBuilder taskBuilder = new BackgroundTaskBuilder
{
Name = "Task",
TaskEntryPoint = "Background.Task"
};
taskBuilder.SetTrigger(new TimeTrigger(15, true));
BackgroundTaskRegistration myFirstTask = taskBuilder.Register();
Background task is created in the Windows Runtime Component as a separate class:
public sealed class Task : IBackgroundTask
{
public async void Run(IBackgroundTaskInstance taskInstance)
{
BackgroundTaskDeferral deferral = taskInstance.GetDeferral();
//logic, send http get request, connect to db
deferral.Complete();
}
}
When it is time to perform task- it may run random number of times (1 - 15 times) and then spontaneously terminated and no longer starts,to solve this problem need to re-register task. What could be the reason?
VS show this error when i want run task:
On Windows Phone periodic background tasks are executed at an interval of a minimum of 30 minutes.
Windows has a built-in timer that runs background tasks in 15-minute intervals. Note that on Windows Phone, the interval is 30 minutes.
(Source: https://msdn.microsoft.com/en-us/library/windows/apps/xaml/hh977059.aspx?f=255&MSPPError=-2147217396)
If I were you I'd change the time interval to something more safe (such as 60 minutes) - you can always try smaller intervals later. And take a look at the oneShot flag, which is set to true in your case. Set it to false to make your task run more than once.
Also your exception does not look healthy. You said it even occurs with the background task being empty - you should fix that, just to be safe.
I'd suggest you to manually start and debug your backgorund task a couple of times using the lifecycle feature in Visual Studio. Maybe there are other things that cause your task to die.
But first check the interval.
I’ve been scratching my head for days about this problem. I’m trying to get a timer that restarts the application every 50s. The code basically fetches database items every 50s and does something. However it seems to hang overnight when there has been a long period of inactivity. I've just shown a skeleton of the code below. In the code also theres’s a connection to a mysql db, rest hhtpwebrequest, and a ssh using renci.ssh to get to another computer. All these are closed properly.
static void Main(string[] args)
{
Timer timer = new Timer(state => workDone(), null, 50000, 50000);
workDone();
}
private static void workDone()
{
//Hold program open for next cycle
Console.ReadLine();
}
Somewhere towards the end of my code i also used Console.ReadLine(); to hold the program open. Is there a reason why this should hang after a period of inactivity? I have a suspicion it’s my code but it may also be the linux box? Will post the whole code if need be. Thank you so much for all your help. Cheers.
I guess you are trying to do this:
private static Timer timer;
static void Main(string[] args)
{
timer = new Timer(state => workDone(), null, 0, 50000);
// Hold program open...
Console.ReadLine();
}
private static void workDone()
{
// Do work
}
I think that by blocking in the callback you'll eventually use up the threadpool.
From MSDN:
The method specified for callback should be reentrant, because it is called on ThreadPool threads. The method can be executed simultaneously on two thread pool threads if the timer interval is less than the time required to execute the method, or if all thread pool threads are in use and the method is queued multiple times.
In your example the time to execute the callback is taking indefinitely long as it is blocking while waiting for user input.
If you want to perform such computation, I suggest you to have one independent thread that will contain a Sleep(50000) call inside. The reason is that if your computation takes more than 50 seconds you might end up with an overhead.
So in your thread measure the start time, do your computation, measure the end time, then compute the computation time and do a sleep of 50 seconds - "computation time". Ensure that this number is positive and put a 10 second minimum sleep in order to let some slack to the other tasks if the computation was longer than 40 seconds.
Thread thread = new Thread(new ThreadStart(myThreadFunction)); thread.Start();
then:
public void myThreadFunction()
{
Stopwatch stopWatch = new Stopwatch();
while(someCondition) {
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
doWork();
stopWatch.Stop();
long elapsed = stopWatch.ElapsedMilliseconds;
if(elapsed < 10000) elapsed = 10000;
Thread.Sleep(elapsed);
}
}
**doWork() does not have the ReadLine call.
trying to set timer for each different threads with different timings , as far as i know if we set a timer in main method the same will works for all the threads, so i want to know how to set timer for each different thread with out killing the threads, kindly advice on this please
static Timer _timer;
static void Main(string[] args)
{
_timer = new Timer(10000);
_timer.Enabled = true;
_timer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
the above pasted code will do job for all of the threads will run for every ten sec, how ever all threads will run for every ten sec by the timer in main method, my concern is have to set timer for each thread with different timing
Summary:
why i asked like this question, here i have requirement of window service,what is to do means,For example in a window service having a three different threads(XYZ,ABC,PQR), if i start a service,all the three threads to be intialized and those threads should to be acts as For which based on timer settings which we are passing from the app config,these thread has to be fire based on the timings has setted,kindly advice
If you want to start some threads after a given time, you can use System.Threading.Timer.
int[] times = new int[] { 10000, 14000, 17000 };
foreach (int time in times)
{
System.Threading.Timer t = new System.Threading.Timer(MyTimerCallback, null, time, 0);
...
}
private void MyTimerCallback(object state)
{
//Do some awesome stuff
}
Have you tried to use the [ThreadStatic] attribute?
This attribute defines that the veriable it coupled with will not be shared between threads, and a copy of him will be created for each thread.
[ThreadStatic]
static Timer _timer;
void MyThreadStartMethod()
{
_timer=new Timer(value);
...
}
And also, i don't see any threads in your code. The Main method is called by the CLR to start the application, and runs each time in a different process.
I'm trying to write a Windows service that runs indefinitely. Windows forms and background programs for Linux don't seem too bad but maybe I'm just horribly inept at Windows Services. Unlike some other sleep or timer related questions I've dug through here, the time to wake up or sleep can be a regular interval, but isn't always such. The program reads from some data files that may instruct it to change its own schedule and this must take effect as of its next wake up time. It seemed quite easy as a console program and behaved perfectly there:
while (true)
{
// Calculate next time to run.
DateTime nextRun = NextWakeup();
TimeSpan nextTime = nextRun - DateTime.Now;
int sleepMs = (int)nextTime.TotalMilliseconds;
// Sleep until scheduled time
System.Threading.Thread.Sleep(sleepMs);
// Do a code cycle of more stuff here...
}
However, when I try to run it as part of a service so that it continues to be active while the user is logged out, the Service Manager stubbornly refuses to start it. I get the lovely 1053 error, "The service did not respond to the start or control request in a timely fashion."
A lot of answers to related questions here seem to suggest going with a timer at all costs over thread sleeping. If I did such a thing instead of the while/sleep combination, how would I go about changing the timer interval at each run? Or is this all perfectly fine and I'm going about setting up my service wrong?
Much thanks in advance!
Windows services must usually respond to a control request (ususally start/stop but also pause/resume) in 30seconds. This means that if you sleep the main thread in the OnStart your service will return the error you refer to.
The way to resolve your issue is to do your work on a separate thread, where you're free to sleep the thread in the way you describe. Just start this thread in the services' OnStart and you should be able to easily return within the 30 second limit.
As an aside, instead of while(true) you should consider the service being stopped must also return in that 30 second limit. If you have a thread sat sleeping the service will not shut down properly without either Aborting the thread (bad) or providing some mechanism for properly exiting the thread. This is exactly why most people go with the polling approach; the service can both determine whether its time to run, or determine whether a stop request has taken place. As long as this poll freqency is <30s the service will always shut down properly.
If you want to use timers its quite easy to do. I'd use System.Timers.Timer and changing its interval is as easy as mytimer.Inverval = nextTime.Seconds or similar.
I'd personally run the timer without AutoReset = false (so it doesn't restart the timer automatically) and then every time it wakes up it runs your "dowork" and then at the end of the dowork you work out when you want it to run next, set the interval as appropriate and then call Start on your timer again.
Of course in your service your start method just sets up the first timer run and then returns so that the startup is nice and quick. On shutdown you just clean up your timer (stop and dispose and such like) and then just return. Nice and clean.
I think you might be looking for something like this:
static class ConsoleProgram
{
static void Main()
{
ServiceBase[] servicesToRun = new ServiceBase[] { new MyService(config, Logger) };
ServiceBase.Run(servicesToRun);
}
}
public partial class MyService : ServiceBase
{
private bool _stopped = true;
protected override void OnStart(string[] args)
{
StartTimer();
}
protected override void OnStop()
{
StopTimer();
}
public void StartTimer()
{
_stopped = false;
Timer t = new Timer(TimerProc);
// Calculate your desired interval here.
t.Change(_config.Interval, new TimeSpan(0, 0, 0, 0, -1));
}
public void StopTimer()
{
_stopped = true;
}
private void TimerProc(object state)
{
// The state object is the Timer object.
Timer t = (Timer) state;
t.Dispose();
ThreadPool.QueueUserWorkItem(DoWork);
if (!_stopped) {
StartTimer();
}
}
}