Avoid the "top of the minute problem" - space out your cronjobs


On Unix the universal job scheduler is "cron" (the other universal but less commonly known daemon is the at daemon). On Unix systems everywhere, lots and lots of batch jobs are kicked off all day from the cron daemon. The typical configuration looks something like this:

18 2 * * * ~/bin/some_batch_job

This means at 18 minutes past the hour at 2am on every day of the month of every month of every weekday, run the following command (You can read about the configuration format by typing man 5 crontab on the command line of a nearby unix-y system).

Why 18 minutes past the hour? For an hourly job you often want to pick a "semi random" time of the hour to run the job. If you run the same batch job on several servers all accessing a shared resource for example.

Sometimes though then the configuration has to be exactly the same everywhere, but you still want to spread out the runs. Or it's a job that runs every minute or two on many systems. Or you have a system that just runs a lot of cronjobs and you can't have them all start at exactly the same second. You have to introduce second granularity to spread them out. But how? The cron format works with minutes at the lowest granularity.

You use the magic $RANDOM variable in the shell!

You can get a random number by just accessing $RANDOM, try it:

echo $RANDOM

If you want a number between 1 and 10 you do a modulo operation on the random variable. In shell syntax that'd be

echo $(expr $RANDOM % 10)

The $( ... ) syntax works like backticks, runs the command and returns the result. The expr command runs the arguments as a shell expression.

Now if you want to run a command (on average) every two minutes, but spread out the executions over 90 seconds, you can do

*/2 * * * * sleep $(expr $RANDOM \% 90); ~/bin/batch_job

This will run the cronjob every 2 minutes (120 seconds), but wait between 0 and 89 seconds before running the actual script. Magic!

Whenever you setup something to access a remote resource (RSS feed, NNTP server, ...) it's always polite to do this, otherwise the server operator will get an onslaught of requests exactly on the minute -- or even worse at the top of the hour.


random and modulo = not-so random

As $RANDOM returns values between 0 and 32767, $RANDOM mod 10 will return slightly more values of 0-7 than 8-9. Be careful where you use such a simple modulo!

Hi Odi,

Good point, thank you. I usually use it just for picking a number of seconds where the average number is as high or higher than the number of cronjobs I want to spread out, so it's been insignificant to me. I should have thought of mentioning it -- or at least not used 10 as an example. :-)

- ask

Be careful that your root's shell is ksh or bash - otherwise this won't work.

Leave a comment

About this Entry

This page contains a single entry by Ask Bjørn Hansen published on November 19, 2007 9:10 AM.

Find recent content on the main index or look in the archives to find all content.


OpenID accepted here Learn more about OpenID
Powered by Movable Type 4.33-en
/* bf */