Welcome to part II of this series. Here is Part I and here is Part 0.
Today we will talk about scheduling unattended tasks.
The classical way to do this in Unix is using the at and cron systems.
I say systems because they are not simple commands, they are a whole set of commands and daemons. Or rather two of them.
On one hand, you have at, atq, atrm, batch and atd.
On the other, there's crond and crontab.
So, all things considered, there are 7 commands you need to consider to manage unattended tasks [1].
While one of the pillars of Unix is that each command should do one thing and do it well, we have here one of the most peculiar results. You have seven commands to do one or two things, and they do them rather badly.
What's wrong with them?
The usual reason for having two command sets is:
Let's see that again.
There is absolutely no reason why you should have two sets of programs with completely different workflows, syntaxes, CLIs, spools and whatever else for this. It's trivial to extend either one to do the job of the other.
But it's not done because...
Look at the Debian package page for cron and for at. These are the most common (but not the only) implementations used on Linux distros.
First unusual thing: they have no webpage. You know why? Because their last release is from when webpages were not all that common.
In the cron sources, the newest file is dated 08/06/96.
In at, it's dated from last year, but that's a bit deceiving: look at the at changelog:
Yes, this piece of software sees maintenance every two years or so. And it's not because it's finished and perfect, it's fixing things like "allow usernames longer than 8 characters" in 2005!
Did I mention that...
Yup. 1996 code.
Which is why these programs....
First, cron (keep in mind that this is just an example, there are dozens of things cron can't do right).
Here's how you run a cron job on the last day of each month (a common business use case):
0 3 * * * if [ "`date -d tomorrow +%d`" = 1 ]; then run_the_script; fi
Of course that may work only on Linux, check this discussion for more fun.
That's also the answer to "How do you run a cron job every X minutes" when X is not a divider of 60. Or every Y hours, when Y is not a divider of 24: run it every day/hour/minute and make it fail when it shouldn't run.
Now think about how to make it run on the last monday of each month. Come on, I give you ten minutes to figure it out.
Now, let's conside at.
Here are some examples of time specification syntax that work with at:
teatime + 4 hours tomorrow now + 6 hours now + 23 minutes 10am Jul 31
And here are some that don't work:
now + 6 hours 23 minutes now + 6 hours + 23 minutes Jul 31 10am
What on earth is that syntax? What's wrong with simply specifying a date and time / a time from now?
By the way, here's what the at man page tells you to read to know the way to specify a time. Please, please check it out. It's a yacc grammar. Yes. You are supposed to understand yacc grammars to figure out at.
Now, assume I scheduled a job (just "ls /tmp"), and want to change it. Here's what I get to work with (not for the weary):
#!/bin/sh
# atrun uid=500 gid=100
# mail ralsina 0
umask 22
MANPATH=/usr/man:/usr/X11R6/man:/opt/java/man:/opt/java/jre/man:/opt/kde/man:/opt/plan9/man:/opt/qt/man:/opt/qt4/man; export MANPATH
:
:
ANOTHER 50 lines of environment variables
:
:
cd /mnt/centos/home/ralsina || {
echo 'Execution directory inaccessible' >&2
exit 1
}
ls /tmp
The idea seems to be running the job in conditions as close as possible to the moment you scheduled it. Although that's already arguably wrong (I prefer my scheduled tasks to run in a controlled environment, not in whatever mess my xterm is!), I am pretty sure there is a way to do this less messy. Like a "edit environment" switch separate from "edit the job".
So, if cron and at suck, what should you use? Well there are some...
If you are going to keep on using the cron/at system, please don't use those. Investigate alternatives, here are a few pointers.
One conservative alternative for cron is bcron [2]:
On the other hand, it adds no new features, and cron really needs some.
There is also fcron:
Bruce Guenter (author of bcron) claims fcron has some issues like lack of /etc/cron.d and /etc/crontab and some parsing incompatibilities with Vixie cron, but I have not verified it, and they look like you can work around them.
There are other crons:
Dillon's cron, last updated in 2005.
Based on Vixie cron, last updated in 2002.
An interesting cron aiming to be small, secure and not rely on mail for notifications.
Last updated in 2005.
Written in Guile, allows for alternative config files in scheme. Interesting but a bit exotic for my taste. Last updated in 2006.
I am sure I am missing a few more.
At replacements:
Regular at, without the too-smart syntax. There seems to be no support for running commands as different users unless each runs a copy of the daemon, so I don't recommend this.
That's it. I can't find a decent implementation of at [3]. Sucks, doesn't it?
But maybe you don't need to use these because there are...
If you are willing to be more daring, you can consider alternative job scheduling systems.
Here are some I have found:
Advantages:
Disadvantages:
Several batch scheduling systems.
This will not be an easy ride. Since your distro is currently planned around at and cron, when you install sotware they will also install cron jobs. If you switch completely to a non-compatible system, then many tasks will simply not be executed, and your system will rot.
And really, there are a bazillion packagers and software writers and distro managers and getting them all to abandon cron/at is not going to happen soon.
So, maybe we could have...
Do a reasonable scheduler (something like uschedule) and add compatibility layers.
Create a daemon. One that doesn't run as root (like bcron's or uschedule's).
That daemon will take care of running the tasks.
Add an interface, one that makes sense, like a DB of scheduled tasks, with a 21st century syntax and capabilities (ie: not cron's). The interfaces mentioned below are simply translated into this.
This is the preferred interface. The others are just compatibility layers. Say that a lot. Give the admins nice web-based GUI-based and CLI-based interfaces to this.
Add to that daemon a Vixie-cron compatible interface (ie, crontab command, /etc/crontab, /etc/cron.d). Again, bcron already has this, uschedule doesn't (sadly). Maybe hack something out of both?
Implement an at command that schedules tasks against that daemon. Doing this for uschedule should be pretty simple, specially if you ignore most of the crazy at syntax.
It should not be terribly hard to do. But we won't see it anytime soon.
| [1] | I know atq and atrm are symlinks to at. |
| [2] | See Bruce Guenter's Problems with other cron systems too. |
| [3] | You have no idea how hard it is to look for information about something called at. |