Introduction
The Cron
class provided with this article implements a small and effective Cron implementation for Windows.
Background
You can schedule the execution of Windows programs using the Scheduled Tasks Control Panel application, and there are already many CodeProject articles related to scheduling in other fashions. So if you are reading this article, I am going to assume that you already have your reasons to implement Cron-style scheduling in C#.
This Cron scheduler is originally part of an application I created for my work, but I have separated out the Cron
class for this article. (BTW, I have written the code using Java-style initialCaps on the methods and associations. You'll just have to live with that or change it yourself.)
Using the code
The Cron scheduler is implemented in a single class, CronService.Cron
(CronService
is the namespace I thought up for this article, but you may want to change this into the default namespace for your Cron application).
You can start an instance of this class using the start()
method, which simply starts the scheduler and never returns. For instance, you can link the code below with the Cron
class to create a regular Windows executable (for use in Windows' Startup Programs folder, for example):
Collapse
|
Copy Code
using System;
namespace CronService
{
class CronMain
{
[STAThread]
static void Main(string[] args)
{
Cron cron = new Cron ();
cron.start ();
}
}
}
I could imagine that you want to create a Windows service instead. To learn how that is done, I recommend the CodeProject tutorial Creating a C# Service Step-by-Step by Terry Denham.
Once you have set up a Windows service like described there, it is a simple matter of filling in the template ServiceBase
class that you have created. There is only one small caveat: the OnStart
method that you will implement here, is expected to return after 20 seconds or so, so you will have to start the perpetually running scheduler in a separate thread.
The example below provides you with a very stripped down version of doing just that. Please use this code only as a hint when creating your own service.
Collapse
|
Copy Code
using System.Threading;
namespace CronService
{
public class CronService : System.ServiceProcess.ServiceBase
{
private Cron cron;
private Thread thr;
public RecoveryService()
{
cron = new Cron ();
thr = new Thread ( new ThreadStart (cron.start));
thr.Name = "cron";
}
protected override void OnStart(string[] args)
{
thr.Start ();
}
protected override void OnStop()
{
thr.Abort();
}
}
}
Creating a valid Cron file
The Cron
class reads a file cron.tab from its current directory. The syntax of this file is as good as compatible with that described in the UNIX manpage crontab(5).
Environment variables and percentage signs for newlines are not supported, and, unlike the original Cron, the command line is not interpreted by a shell. Instead, the first word is assumed to be the executable, and the rest is passed as arguments to this executable using the System.Diagnostics.Process
API.
As crontab fields are separated by whitespace, a single preceding backslash may be used to escape a space character in the command field. And to be complete, a double backslash may be used to escape a single backslash when it's unfortunately placed before an unsuspecting space character. At any other place, a single backslash will do just fine.
An example:
Collapse
|
Copy Code
# DoThis every hour
0 * * * * C:\Program\ Files\MyProg\DoThis.exe arg1 arg2
# DoThat -- well, you figure out when :-)
8-9/2 12,13,14-18 * * * C:\Program\ Files\MyProg\DoThat.exe
Points of Interest
The Cron
class is small and effective, but did I mention small? There are some limitations that you should be aware of:
- Cron only reads the cron.tab file at startup. You need to restart Cron if you want changes to cron.tab to become effective. There are no multiple crontabs, nor is there a
crontab(1)
command.
- Cron does not mail any program output to the system administrator, as you may be used to from UNIX. Instead, it only reports when a program exits with a nonzero exit code.
- The
reportError()
function is left empty as an exercise to the reader.
Closing note: while Paul Vixie achieved immortality with his Cron implementation, I wrote mine in a single day or so. This is of course mainly due to the advanced DateTime
and String
functions available in the .NET API.
The code within this tutorial is free to use, but please, credit where credit is due.
History
- July 14, 2005 -- First version of this article.