Executing scheduled tasks with Fcron

Job Clock


Fcron does everything Cron can do, plus it delivers a few extra tricks to work around the downtime.

By Matija Ķuklje

Orlando Rosu, 123RF

Linux admins and many other users are quite familiar with the classic Cron utility, a text-based job scheduler that automates the execution of re-occurring tasks. If you are not familiar with Cron, you'll find several discussion online [1].

Cron has been around for a long time, and it has undergone many stages of evolution, but most modern Cron implementations (Vixie Cron/ISC Cron, BCron, DCron, ...) are still based on the assumption that your system is running 24/7. Unfortunately, unless your system is a dedicated server, it is probably not running 24/7. Users suspend and shutdown laptops to carry them around, and even our desktops and workstations typically spend some downtime to preserve energy. The result is that cronjobs fail regularly because the system is not up at the precise time when the job is supposed to execute.

To work around this problem, some distributions offer Anacron as an alternative to Cron. Anacron lets you create a checklist of tasks that need to happen at predefined intervals, and when Anacron starts, it looks at that list and performs any tasks that haven't happened yet. Anacron, however, has some limitations. First, because it is not a daemon, it must be executed every time it is needed - either manually, or by boot scripts, or by Cron. Second, Anacron isn't designed to handle time periods smaller than days. The combination of these problems can lead to scenarios in which both Cron and Anacron are operating at the same time, and the same task executes either twice or not at all.

Fcron [2], on the other hand, is a Cron alternative that does what both Vixie Cron and Anacron can do, plus a lot more. You can use Fcron to schedule cronjobs by fixed time and date, time interval, or even system uptime.

Glossary

A cronjob is a task that a Cron system is instructed to run periodically. The crontab file is a configuration file for a user that defines tasks to run under the user's account. The systab file is a file that specifies cronjobs for the system. Fcron's own crontab system uses the fcrontab file for configuration information. The fcrontab syntax is similar but differs slightly from the classic Vixie/ISC Cron crontab notation.

Getting Started

Fcron is available in package form for most modern GNU/Linux distributions - all you have to do is find the package (it's usually called "fcron") and install it with your distro's package manager.

To create an fcrontab file, run the following command in your terminal:

fcrontab -e

To edit your system fcrontab file, enter the following (as root):

fcrontab -e systab

When your default text editor opens, you can start adding entries to the fcrontab file.

Note that, to accommodate Fcron's additional features, the syntax is slightly different from the syntax used by Vixie Cron.

Cronjobs Defined by Fixed Date and Time

To begin, I'll start with something any Cron can do - a simple job that makes a backup copy of a document every working day at 3am:

& 00 03 * * mon-fri cp ~/Documents/Importaint.odt /mnt/backup/Importaint.odt~

When you save and exit your editor, Fcron will automatically save these entries. Even before that, Fcron will test the syntax of all cronjobs and prompt you to correct any errors.

The ampersand (&) at the start of the line tells Fcron that this is a cronjob with a fixed date and time. After that, you will find two time fields and three date fields: minutes, hours, day-of-month, month, and day-of-week. The preceding example specifies the following time: 00 minutes, 03 hours, every day in the month, every month, and from Monday to Friday. At the end of the line comes the command you want to execute at the specified time.

When writing fixed-time cronjobs, you have to fill in all five date and time fields, so you should use the asterisk (*, meaning "all") if you don't plan to write any restriction in a particular field. In the preceding example, you didn't care which month or day in the month it was, as long as it was a day from Monday through Friday.

For convenience, you can use three-letter abbreviations of month names and days of the week instead of numbers. Also, you can use lists (separated by commas), ranges (connected with a dash), skips in ranges (preceded by a slash), and exceptions in ranges (preceded by a tilde).

Consider the following cronjob, which annoys you with a notification every 20 minutes from 9am to 4pm every day from the 10th until the 25th of March, with the exception of the 15th (because you're free that day).

& 00,20,40 9-16 10-25~15 mar * echo "Are you done yet? Are you done yet?"

Another real-life example would be if you want to run a script in your home directory every other day at 4pm and have the output emailed to your boss automatically:

&mailto(boss@office.com) * * */2 * * ~/script.sh

In this example, you can also see one of the options that you can set for Fcron's cronjobs. More about these options is described at the end of this article.

So far, you probably aren't impressed enough to switch from the default Cron that comes with your distribution. But Fcron offers some additional features that make it more than the ordinary Cron.

Fcron Settings

Fcron configuration files are similar to the Vixie Cron implementation (which is the default in most distributions). On my Gentoo system, these files reside in /etc/fcron/ :

  • fcron.conf - lets you specify your preferred text editor, mailer program, and a few other settings.
  • fcron.allow - specifies which users are allowed to use Fcron (all means every user can have an fcrontab file).
  • fcron.deny - specifies users who you do not want to use Fcron (overrides the settings of fcron.allow).

The defaults should be OK, unless you need extra restrictions.

In addition to scheduled tasks, the fcrontab file can include environment settings (for instance, HOME and SHELL variables). If, for instance, you're concerned about security and want to override your shell settings from /etc/passwd, you can write the following to your fcrontab file:

SHELL=/bin/sh

Cronjobs Defined by Interval

Chances are that, unless you're running a server, your system is not up 24/7, so scheduling jobs by a fixed date and time will lead to many lost jobs.

Luckily, Fcron has a feature that lets entries run within pre-defined time intervals. If the system is running at any time in that interval, the job gets executed. I think this feature is the most useful part of Fcron. On my laptop, almost all the system cronjobs are set up this way. Consider the following entries:

%daily,nice(7) * 10-14 makewhatis -u
%daily,nice(7) 30 16-18 updatedb

These entries are from my systab (the system fcrontab file). The % at the beginning of the line tells Fcron that what follows is a cronjob defined by an interval. Next is a keyword that describes what type of interval you're trying to set. The keyword could be a term such as hourly, daily, weekly, or monthly, or it could represent an absolute time measure: mins (minutes), hours, days, dow (day of the week), or mons (months). Each of the two keyword types acts differently. The *ly keywords are self-explanatory: daily runs the cronjob daily, and weekly runs it once sometime from Monday until Sunday and then waits for the next week to begin.

After the comma, you can see another option, nice, which runs the cronjob with the nice level enclosed in parentheses. (The nice utility changes the priority of a process in the kernel's scheduler.) Next is the date and time fields needed to define the time interval, then the command. So the preceding cron entries update the man pages (makewhatis -u) every day, if the system is up sometime from 10:00am until 2:00pm (10-14), and updates the slocate database (updatedb) if the system is up sometime from 4:30am through 6:30pm (30 16-18).

The preceding example uses the daily keyword, which has to have the interval set in minutes and hours. The same is true for weekly. By analogy, hourly needs only the minute field, and monthly needs the minutes, hours, and days.

If you specify mid with one of the *ly keywords (middaily, midweekly) the interval starts and ends in the middle of the given time frame. For instance, midweekly runs the command between Thursday of this week and Wednesday of next week.

The cronjob

%hours 20,40 9-10 * * * finger boss

runs every day only once at 9:20, 9:40, 10:20, or 10:40 because, when using hours (or any of the other *s keywords), Fcron ignores all time fields that are smaller than the keyword. But if such a field is set (other than with an asterisk), Fcron will take this into account for defining the time when the cronjob should be triggered.

If the preceding example used the mins keyword instead, the command (checking the last login time and other info of the user boss), would execute at 9:20, 9:40, 10:20, and 10:40 every day because the minutes are a part of the interval.

As you have already guessed from the syntax, the *s keywords offer functionality that is a mix between fixed date-time cronjobs and *ly keywords.

Cronjobs Defined by Uptime

What if you want to make the execution of a job dependent on your system's uptime? Sure, you could write a complex script with a loop and a sleep function in it, but why not do it more elegantly? Fcron can even run specific cronjobs at times calculated from the system uptime (or, more precisely, on the basis of the uptime since the start of the Fcron daemon).

If you want to create a log that stores the load average and a list of users that are logged in every 15 minutes of uptime (e.g., for statistical means), you could use the following entry:

@ 15 w >> /root/user_stats

The @ at the start of the line tells Fcron this is a cronjob that accounts for system uptime. After that is the time frequency set in minutes. And last but not least is your command.

For example, say you want to receive a nice email on your system's uptime birthday - that is, when the system's uptime increases for a year (a proud day for any admin).

@mail 365d echo "*POP* Huzzah! Your baby is another year older! :D"

The mail option sends an email to the user owning the fcrontab/cronjob (as opposed to the mailto option, which lets you specify a recipient). The frequency field is occupied by 365d for 365 days. Fcron provides the option of defining the frequency with the use of multipliers.

A number representing the number of time units precedes an s for seconds, h for hours, d for days, w for weeks, or m for months. (Please note that the minutes unit has no multiplier.) Additionally, you can combine multipliers, so if you want to execute a script after every two weeks, three days, 10 hours, and 15 minutes of uptime, you could enter:

@ 2w3d10h15 sh /root/script.sh

Options

Options can be defined globally or at the crontab line. An option that resides on a line by itself must be preceded by an exclamation mark (!, with no intervening space). In a normal cronjob line, the options have to follow directly after the @ or & sign - or, in the case of a % line, after the keyword and separated by a comma.

If you set up several options, you should separate them with a comma (without the space). If an option has an argument, you should enclose the argument in parentheses after the option. Options in cronjob lines always override global options, and all options can't be used with all cronjob types.

The line

&bootrun(true),nice(8) 30 3 * * * python /root/admin_report.py

runs your root python script every day at 3:30am (30 3). The nice(8) option runs the process at nice level 8. (Nice levels range from -20, the highest priority, to 19, the lowest priority.) Although the & specifies a fixed time for the script, the option bootrun(true) ensures that the job will still run when the Fcron daemon starts. The following series of entries:

@first(5) 1h sh one_script.sh
@first(10) 1h sh another_script.sh
@first(20) 1h sh yet_another_script.sh

sets up three scripts to run every hour of uptime.

Without the first() option, all three scripts would try to run at the same time. The values specified with first() ensures that the jobs will start at different times. The first script will always run five minutes after another hour of uptime, the second every 10 minutes after another hour of uptime, and the third every 20 minutes after another hour of uptime. In other words, one_script.sh will be run at 1:05, 2:05, 3:05, ... of uptime; another_script.sh will run at 1:10, 2:10, 3:10, ... ; and yet_another_script.sh will run at 1:20, 2:20, 3:30, ... .

Now I'll use the mailto option introduced earlier with the random option to pick a random time in the time interval, instead of running the job at the earliest possible time within the interval:

%daily,random,mailto(tux) * 8-20 ping example.com

The preceding cronjob will ping the server at example.com every day at a different time between 8:00am and 8:00pm and then mail the output to the user tux.

Conclusion

Fcron can do everything Vixie Cron and Anacron can do - but better and with more control and fewer caveats. For more on Fcron, see the documentation at the project website [3].

INFO
[1] Cron: http://unixgeeks.org/security/newbie/unix/cron-1.html
[2] FCron website: http://fcron.free.fr
[3] Fcron documentation: http://fcron.free.fr/doc/en/index.html
THE AUTHOR

Matija Ķuklje is a law student with a great interest in IT, FOSS, and intellectual property law. He's been an active GNU/Linux user for more then a decade. He writes about FOSS and law (and tea) at his homepage http://matija.suklje.name, where you will also find his contact details.