Rotten Scheduling: Don’t roll your own
“We need to run a specific task every 72 hours, I thought about this approach…”
public class TimedTask { public static Timer Timer; public static void Init() { Timer = new Timer(ExecuteEvery72Hours, null, TimeSpan.FromHours(72), TimeSpan.FromHours(72)); } public static void ExecuteEvery72Hours() { // do something important } }
This is a bloody rotten idea, let us see why…
- What happens if your application is recycled every 29 hours?
- What happens if your application is always on, but during that 72 hour call, it was offline?
- What happens if your task actually takes more than 72 hours to run?
- What happens if the task fails?
- How do you report errors, warnings, etc?
Scheduling is a hard problem. There are a lot of things that you actually need to consider. And the code above is really considering none of them. I would be very surprised if something like that ever run. in production. It most certainly can’t be made to run reliably.
Things that run every X time, where X is a long time (hours / days) tend to be pretty important. In some of the systems that we wrote, that include doing things like updating VAT and interest rates, pulling from external source, generating the weekly report, etc.
You do not want this to be messed up.
If you need to do anything like that, make use of the builtin scheduling features of the OS you are running on (Windows Task Scheduler is an amazingly full featured, and cron isn’t bad if you are running on Linux). If you still insist on doing this in code, at the very least do something like this:
public class TimedTask { public static Timer Timer; public static void Init() { Timer = new Timer(()=> { if( (DateTime.UtcNow - GetLastExecutedTime()) > 72) ExecuteEvery72Hours(); }, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); } public static void ExecuteEvery72Hours() { // do something important } }
This still has a lot of problems, but at least it it solving some crucial problems for you (note that GetLastExecutedTime has to be a persisted value).
Of course, if you need something like this in your code, you have better use something like Quartz, instead. Don’t roll your own. Sure, this is ten lines of code to do so, but as I said, this is the very basics, and it gets complex really fast.
Comments
Why would you not use http://quartznet.sourceforge.net/ + topshelf
Or use a scheduling framework like Quartz.NET (http://quartznet.sourceforge.net)
We use Quartz.NET with Topshelf in production, found it to be very reliable. Add decent logging and email notifications on success/error and you can near enough "set and forget" it.
I agree on using the builtin scheduling features of the OS. Writing code makes it more complex and a source for bugs and problems and more code to maintain.
Quartz is an overkill for such a simple task - .Net gives you timers so all you need to do is to store job status & execution time somewhere... Don't make a pig of your application by adding unnecessary external dependencies, writing the execution time to a file is easier to do than learning quartz.net or topshelf.
To schedule on Windows Task Scheduler need I create a simple console application to put it there?
I think Ayende is talking about a one-off in a project so for simple tasks, sure, learning Quartz (and Topshelf) would be overkill. But when you start getting a collection of scheduled tasks, all running on different triggers, sharing logic and data layer etc, Quartz provides a decent framework and enforces patterns via IJob. Doesn't have to impact on the main app too much (or at all) if it's in its own solution whilst referencing only the projects it depends on from the main app's solution.
Windows Task Scheduler + a console application is the way to go.
Simple, easy to debug and sys admins can go in and mess around with scheduling if they so desire.
There are a number of Task Scheduler wrapper libraries you could use, such as http://taskscheduler.codeplex.com/
+1 James for console + win scheduler (only on win, of course)
@James The sys admin thing is the main reason why i stopped using windows task scheduler and moved to quartz.
My app needs something done every 72 hours? great. it is still a part of my app. Let me administer that myself (if needed, let the power user access to tasks admin page).
One of the worst things that can happen in production, is that a time sensitive task runs since some idiot decided to right click and ran it. Task scheduler won't even tell you who did it.
Moti...that sounds more like a people problem than a technical problem. I see the ability to manually run something as a big win in the flexibility column.
If I am alreading using SQL Server, does anyone have a reason to not use it as a scheduler?
http://msdn.microsoft.com/en-us/library/ms187880
Thanks for letting me know about TopShelf guys!
@Daniel: If you run SQL jobs then ok.
@nyt - win only? *nix has crond
OS schedulers are pretty darn good.
Oh come on, unix has console too but it's lame compared to windows cmd.exe
@Ken: i was referring to task scheduler specifically, that's only on windows. on *nix there's cron, i agree
@Gene
I do provide the ability to run the quartz tasks manually, I just do it from my own interface and application, under my own security model, under my own business logic (some tasks I won't allow running during work hours, unless you mark the application as 'down for repairs'), under my scalability model - basically, under my terms.
I want full control over my app. I can get it with task scheduler as well, but i have to work twice as hard.
Comment preview