Monday, May 14, 2012

Rotten Scheduling: Don’t roll your own

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.


ICT4PE&D

No comments:

Post a Comment

Thank's!