fcron is the best cron

Common cron versions suffer from historical limitations, making it harder than necessary to set up recurring tasks the way you want. On this page, I enumerate some of the limitations, examine systemd timers as an alternative, and then explain why I use fcron.

Here are some limitations of cron that I have had to work around.

  • cron emails you if there is any output from the job, even if the job succeeds.
  • Vixie Cron has no way of running tasks at a random time within an interval. RANDOM_DELAY, present in some versions, is calculated once per daemon restart, not per job or per run. While this mitigates the thundering herd problem for identical machines, it does nothing for jobs on the same machine. I have arrived at prefixing demanding cron jobs with a command like perl -e 'sleep rand(30 * 60)' or sleep "$( jot -r 1 0 $(( 30 * 60 )) )" in order to distribute system load.
  • cron does not prevent another copy of the same job from running. Users work around this with locking, often with flock(1), or scanning the process list with pgrep(1). When locking fails and leaves the lock file in place, the job won’t run. When scanning the process list fails, multiple copies of the job can run.
  • cron can’t spread out heavy tasks. The user usually implements locking per-job.
  • cron does not run jobs that were missed because the system wasn’t running. anacron addresses this—however, only for system-wide jobs. Users do not get their own anacrontab(5).
  • Commands are limited to a single line in cron. You should write scripts, but for a job that is two commands long, you probably won’t.

The leading alternative to cron is systemd timers. While timers address cron’s lack of randomization and locking, the first thing you notice about them is that they are less ergonomic. Timers require two systemd unit files per job. That timers separate the unit from the timer and use INI files with multi-word keys seems like reasonable software design, and yet the result is poor UX compared to crontab(5). Timers have no integrated support for email. They are also, of course, not cross-platform.

timertab removes some friction from creating new timers. However, after the creation stage you are left with the same two unit files to manage.

The systemd timer user experience may be a price well worth paying for commercial deployments. I want something different for jobs on my home machine.

I have found a more pleasant-to-use alternative to forks of Vixie Cron and systemd timers in fcron. A project started in 2000 with a period website, fcron is ahead of every cron implementation I know. It addresses some of the weaknesses that lead users to switch to systemd timers, while still providing crontab(5)-style configuration.

The following are the main fcrontab(5) features that I use.

  • @ 1d (an optional replacement for the date-time fields)—jobs can run daily (or every N minutes, hours, days, weeks, etc.), taking downtime into account.
  • serial (per-job option)—only one serial job runs at a time by default. This limit can be increased, allowing fcron to run no more than a certain number of jobs rather than just one.
  • erroronlymail (global option)—as the name suggests, only email the user if a job fails, regardless of whether it generates output.
  • mail(false) (per-job option)—never send emails, even on errors. Useful if you have another way of monitoring a job.
  • Line continuations—your job does not have to fit on a single line.

Fcron can also schedule jobs based on the system load average. I haven’t tried it.

fcrondyn(1) is an interactive shell included with fcron where you can examine, run, renice, and kill fcron jobs. It lets you run a job either as a one-off or instead of the next scheduled run. Jobs are referred to by a numeric job identifier. This is something of a disadvantage compared to systemd timers, which can be given meaningful names.

Fcron can import a Vixie Cron crontab. It is cross-platform. Many Linux distributions package it, and it has a port in the FreeBSD ports tree and MacPorts. (Repology.) It can run via systemd on Linux.

It may be worth writing a program that completely manages systemd timers entrusted to it based on a crontab(5) variant. While there is a translator for Vixie crontabs, the limitations of Vixie crontabs were the reason people started switching to systemd timers in the first place. You could instead translate a file format derived from fcrontab(5) or OpenBSD crontab(5). OpenBSD crontab(5) has the options -n (no email if successful) and -s (only allow a single instance of the command) and will soon have random ranges. This set of features seems possible to translate in full. I think it covers what users want from timers for most jobs.