Is it acceptable practice to create Tasks with long delays? - c#

I'm creating a scheduler to fire events at specific times of the day, and to do this I'm spinning up Tasks (one at a time, i.e. the 'next' schedule only) with a Task.Delay of anything up to a few days delay. For example, after the last event fires on a Friday afternoon, I'll set up the next one which will be some time on Monday, so it could potentially be a TimeSpan of up to 3 days (~260,000,000 milliseconds).
Is this acceptable practice? I'm concerned that this won't be stable/robust enough for a production environment.
Here's some snippets of code to describe what I've put together:
private void SetNextEvent()
{
TimeModel next = GetNextScheduledTime();
Debug.WriteLine($"Next schedule [{next.TimeType}]: {next.Time.ToString("yyyy-MM-dd HH:mm:ss")}");
TimeSpan delay = next.Time.Subtract(DateTime.Now);
Task.Run(async () =>
{
await Task.Delay(delay);
FireEvent(next);
});
}
private void FireEvent(TimeModel time)
{
Debug.WriteLine($"Event fired [{time.TimeType}]: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}");
OnSchedulerEvent?.Invoke(this, new SchedulerEventArgs { ScheduleType = time.TimeType });
if (_running)
SetNextEvent();
}

This is totally reliable. .NET timers are very efficient. The biggest problem is that you must assume that your production apps can exit at any time. The reason that is easiest to understand is a bug that kills the process. Other reasons include reboots, app pool recycles, deployments, ....
So if you can recover your state after being killed this is fine. If you add a comment about specific concerns I'll address them.
It looks like you have a way to recover timers because you apparently can compute the next due time. Under those circumstances it's very safe to do this. You need to ensure that your code is always running e.g. right after a reboot or a crash.
Note, that IIS apps need to tolerate running multiple times concurrently. Otherwise, IIS is a great host for your scenario.

If you're running Windows, I'd use the TaskScheduler to do what you're trying to do.
run taskschd.msc you can use that program to schedule periodic tasks.
There should be an "Create Task..." button in the panel on the right.

I agree that the Windows Task Scheduler is probably the best approach is you know ahead of time the schedule to run the next task.
If you do not know this ahead of time(i.e. the time to wait for the next task can vary) then I would suggest using a timer and an event handler method when the timer expires.
Each time you can set the Interval property of the timer for the time to wait. When the time expires the timer event handler will run and it can execute the ask and reset the Interval for the timer. This seems a little cleaner then a Task.Delay.

Related

Create a delay in ASP.NET 3

I'm stuck in ASP.NET 3, which means I don't get to use the Task asynchronous programming model. In ASP.NET 4 forward, I think I can just safely do await Task.Delay(n).ConfigureAwait(false);, but that's not an option here.
I want to purposely create a one-second delay before responding in ASP.NET, but I want to make sure I'm only affecting the current request and not delaying other users. Thread pools and the like have never been my strong point.
If I use Thread.Sleep(1000), it blocks the current thread - does that mean only this particular request? Or are other requests potentially on the same thread and getting blocked, particularly if there is a decent load of traffic?
Does Task.Delay(1000).Wait() behave the same way?
I've hit deadlocks in the past doing this kind of thing as well, which I never really understood, so would these potentially cause deadlocks with other requests?
I have two scenarios:
First, just inside the controller action:
public ActionResult DoSomething() {
DoSomethingElse();
Thread.Sleep(1000); // Or Task.Delay(1000).Wait() or whatever
return something;
}
I also need both this in a separate task that I kick off from a controller action, like a fire-and-forget, which I call with something like:
Task.Run(() => RunProcess(processID))
.ContinueWith(task =>
{
if (task.IsFaulted) { /**/ } else { /**/ }
}
});
void RunProcess(Guid processID) {
DoAnotherThing();
Thread.Sleep(1000); // or Task.Delay(1000).Wait() or whatever else
}
Thread.Sleep is probably ok. But it depends on your load and what the rest of the request is doing.
ASP.NET does assign a separate thread per request, so if you sleep on one, it won't affect other requests.
That said, there is a maximum number of threads. By default it is 20 thread per CPU core, but it is configurable. See maxWorkerThreads in the processModel Element (ASP.NET Settings Schema) documentation.
So you would only run into issues if you are getting more than 20x[your CPU cores] per second. Then introducing a one second delay in every request would cause the request queue to back up if your load is that high.
You would also have to take into account what the rest of the request is doing. If you have 1 second sleep + 1 second of processing time, then you will start having problems if your load is 10x[your CPU cores] per second. So it's worth timing how long the whole request takes if you think your load might be high.
You can raise the maxWorkerThreads value if you think you might have a problem.
As you mentioned Sleep function of Thread class, it's the exact thing you need and it just sleep the current thread for the amount of time you set, but about dotnet tasks, it's different and dotnet get the thread and use it for other requests until the delay time expires, then one of thread handle the rest of your function.
some of other ways to handle this kinda works ia busy waiting.. Loops that is not good.
Thread sleep:
https://learn.microsoft.com/en-us/dotnet/api/system.threading.thread.sleep?view=netcore-3.1

System.Threading.Timer does not work correctly

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

Unpausing Quartz trigger causes many job executions

I have a job that is scheduled to run every 30 seconds with a Quartz Crontrigger. The schedule is thus "0/30 * * ? * MON-FRI". It has no problem running.
However, I want to pause the job for one minute. So I call scheduler.PauseAll();, which is supposed to pause all triggers in the scheduler. I then have the thread sleep for one minute and then call scheduler.ResumeAll();. So my code looks something like this:
scheduler.PauseAll();
System.Threading.Thread.Sleep(60000);
scheduler.ResumeAll();
The trigger pauses for the appropriate time, but when it resumes, the job will run twice. I have the jobs set with the misfire handling .WithMisfireHandlingInstructionDoNothing(), so I don't understand why the job executes twice in this case. I read this question, but the OP there paused the job instead of the triggers, so I didn't find it helpful.

Creating a c# windows service to poll a database

I am wanting to write a service that polls a database and performs an operation depending on the data being brought back.
I am not sure what is the best way of doing this, I can find a few blogs about it and this stack overflow question Polling Service - C#. However I am wary that they are all quite old and possibly out of date.
Can anyone advise me on the current advice or best practices (if there are any) on doing something like this or point me in the direction of a more recent blog post about this. From what I can gather either using a timer or tpl tasks are two potential ways of doing this.
If timers are still suggested then how will they work when the service is stopped because the operations I intend for these services to do could potentially take 30+ minutes, this is why I say use tasks because I can use a task cancellation token but these throw exceptions when cancelled (correct me if I am wrong) and I don't think I really want that behaviour (although correct me if you think there is a reason I will want that).
Sorry that I may be asking quite a lot in a single question but I'm not entirely sure myself what I am asking.
Go with a Windows service for this. Using a scheduled task is not a bad idea per se, but since you said the polls can occur every 2 minutes then you are probably better off going with the service. The service will allow you to maintain state between polls and you would have more control over the timing of the polls as well. You said the operation might take 30+ minutes once it is kicked off so maybe you would want to defer polls until the operation complete. That is a bit easier to do when the logic is ran as a service.
In the end it does not really matter what mechanism you use to generate the polls. You could use a timer or a dedicated thread/task that sleeps or whatever. Personally, I find the dedicated thread/task easier to work with than a timer for these kinds of things because it is easier to control the polling interval. Also, you should definitely use the cooperative cancellation mechanism provided with the TPL. It does not necessary throw exceptions. It only does so if you call ThrowIfCancellationRequested. You can use IsCancellationRequested instead to just check the cancellation token's state.
Here is a very generic template you might use to get started.
public class YourService : ServiceBase
{
private CancellationTokenSource cts = new CancellationTokenSource();
private Task mainTask = null;
protected override void OnStart(string[] args)
{
mainTask = new Task(Poll, cts.Token, TaskCreationOptions.LongRunning);
mainTask.Start();
}
protected override void OnStop()
{
cts.Cancel();
mainTask.Wait();
}
private void Poll()
{
CancellationToken cancellation = cts.Token;
TimeSpan interval = TimeSpan.Zero;
while (!cancellation.WaitHandle.WaitOne(interval))
{
try
{
// Put your code to poll here.
// Occasionally check the cancellation state.
if (cancellation.IsCancellationRequested)
{
break;
}
interval = WaitAfterSuccessInterval;
}
catch (Exception caught)
{
// Log the exception.
interval = WaitAfterErrorInterval;
}
}
}
}
Like I said, I normally use a dedicated thread/task instead of a timer. I do this because my polling interval is almost never constant. I usually start slowing the polls down if a transient error is detected (like network or server availability issues) that way my log file does not fill up with the same error message over and over again in rapid succession.
You have a few options. To start with what could be essentially the easiest option, you could decide to create your app as a console application and run the executable as a task in the Windows Task Scheduler. All you would need to do is assign your executable as the program to start in the task and have the task scheduler handle the timing interval for you. This is probably the preferred way if you don't care about state and will prevent you from having to worry about creating and managing a windows service if you don't really need to. See the following link for how to use the scheduler.
Windows Task Scheduler
The next way you could do this would be to create a windows service and in that service use a timer, specifically System.Timers.Timer. Essentially you would set the timer interval to the amount of time you would like to have pass before you run your process. Then you would sign up for the timers tick event which would fire every time that interval occurred. In this event you would essentially have the process you would like to run; this could kick off addition threads if you would like. Then after that initial setup you would just call the timers Start() function or set the Enabled property to True to start the timer. A good example of what this would look like can be found in the example on MSDN page describing the object. There are plenty of tutorials out there that show how to set up a windows service so I won't bother with going into that specifically.
MSDN: System.Timers.Timer
Finally and more complex would be to set up a windows service that listens for a SqlDependency. This technique is useful if things can occur in the database outside your application yet you need to be made aware of it in your application or some other service. The following link has a good tutorial on how to set up a SqlDependency in an application.
Using SqlDependency To Monitor SQL Database Changes
Two things I would like to point out from your original post that are not specific to the question you had.
If you are writing a true windows service you don't want the service to stop. The service should be running constantly and if an exception does occur it should be handled appropriately and not stop the service.
A cancellation token doesn't have to throw an exception; simply not calling ThrowIfCancellationRequested() will cause the exception not to be thrown or if this is a CancellationTokenSource set the argument to false on the Cancel method then subsequently check the token to see if cancellation is requested in your threads and return out of the thread gracefully if so.
For example:
CancellationTokenSource cts = new CancellationTokenSource();
ParallelOptions options = new ParallelOptions
{
CancellationToken = cts.Token
};
Parallel.ForEach(data, options, i =>
{
try
{
if (cts.IsCancellationRequested) return;
//do stuff
}
catch (Exception ex)
{
cts.Cancel(false);
}
});

Windows service scheduled execution

If I have a Windows Service that needs to execute a task every 30 seconds which is better to use; the Timer() class or a loop that executes the task then sleeps for a number of seconds?
class MessageReceiver
{
public MessageReceiver()
{
}
public void CommencePolling()
{
while (true)
{
try
{
this.ExecuteTask();
System.Threading.Thread.Sleep(30000);
}
catch (Exception)
{
// log the exception
}
}
}
public void ExecutedTask()
{
// do stuff
}
}
class MessageReceiver
{
public MessageReceiver()
{
}
public void CommencePolling()
{
var timer = new Timer()
{
AutoReset = true,
Interval = 30000,
Enabled = true
};
timer.Elapsed += Timer_Tick;
}
public void Timer_Tick(object sender, ElapsedEventArgs args)
{
try
{
// do stuff
}
catch (Exception)
{
// log the exception
}
}
}
The windows service will create an instance of the MessageReciever class and execute the CommencePolling method on a new thread.
I think it really depends on your requirement.
case 1.
Suppose you want to run this.ExecuteTask() every five minutes starting from 12:00AM (i.e., 12:00, 12:05, ...) and suppose the execution time of this.ExecuteTask() varies (for example, from 30 sec to 2 min), maybe using timer instead of Thread.Sleep() seems to be an easier way of doing it (at least for me).
However, you can achieve this behavior with Thread.Sleep() as well by calculating the offset while taking timestamps on a thread wake-up and on a completion of this.ExecuteTask().
case 2.
Suppose you want to perform the task in the next 5 min just after completion of this.ExecuteTask(), using Thread.Sleep() seems to be easier. Again, you can achieve this behavior with a timer as well by reseting the timer every time while calculating offsets on every time this.ExecuteTask() completes.
Note1, for the case 1, you should be very careful in the following scenario: what if this.ExecuteTask() sometimes takes more than the period (i.e. it starts at 12:05 and completes 12:13 in the example above).
What does this mean to your application and how will it be handled?
a. Total failure - abort the service or abort the current(12:05) execution at 12:10 and launch 12:10 execution.
b. Not a big deal (skip 12:10 one and run this.ExecuteTask() at 12:15).
c. Not a big deal, but need to launch 12:10 execution immediately after 12:05 task finishes (what if it keeps taking more than 5 min??).
d. Need to launch 12:10 execution even though 12:05 execution is currently running.
e. anything else?
For the policy you select above, does your choice of implementation (either timer or Thread.Sleep()) easy to support your policy?
Note2. There are several timers you can use in .NET. Please see the following document (even though it's bit aged, but it seems to be a good start): Comparing the Timer Classes in the .NET Framework Class Library
Are you doing anything else during that ten second wait? Using Thread.sleep would block, preventing you from doing other things. From a performance point of view I don't think you'd see too much difference, but I would avoid using Thread.sleep myself.
There are three timers to choose from - System.Windows.Forms.Timer is implemented on the main thread whereas System.Timers.Timer and System.Threading.Timer are creating seperate threads.
I believe both methods are equivalent. There will be a thread either way: either because you create one, or because the library implementing the Timer class creates one.
Using the Timer class might be slightly more less expensive resource-wise, since the thread implementing timers probably monitors other timeouts as well.
I this the answers to this question will help.
Not answered by me but John Saunders (above)... the answer can be found here For a windows service, which is better, a wait-spin or a timer?

Categories