Cron jobs are executed in an environment different from our normal shell, and this can be a source of all kinds of errors and frustration.
In this tutorial, let’s go through some measures we can take to make it easier to debug the cron jobs we write.
All commands mentioned in this article are POSIX commands and tested in Bash. They should be available in every POSIX compatible shell.
2. The Challenge
The issue which makes it hard to test and debug cron jobs is that they’re executed in an environment that differs from our own. We need a good understanding of these differences to cope with that.
Cron jobs located in these directories are run as root:
/etc/cron.hourly/ /etc/cron.daily/ /etc/cron.weekly/ /etc/cron.monthly/
We can also put them in a cron table, or crontab for short. Each user has their own crontab. All jobs defined in a crontab run as the user that owns it.
To be successful at writing those jobs, we have to write and test it as the same user that the cron daemon will use.
We should always edit crontabs by using the crontab command as it will check the syntax of our expressions.
Cron jobs run in an almost empty environment. The daemon sets a few variables and a minimal PATH containing only /usr/bin:/bin.
We should always use absolute paths in our cron jobs and not rely on the contents of HOME and PATH, or we should explicitly define PATH in our script.
Like most daemons running on our system, the cron daemon logs its output somewhere under /var/log. We check these logs to see if our jobs execute at the right time.
The most popular cron implementation is Vixie cron. Vixie cron logs go to /var/log/cron. These logs show when jobs are executed, but they can’t tell us if errors occurred while the job was running.
In addition, it’s good to add logging to our script. This will help to find out exactly where things go wrong when they do.
The command printenv and the Bash built-in command set turn out to be perfect for this. We add them by placing these lines around the script:
printenv set -x ... our script goes here ... set +x
The printenv command prints all environment variables to standard output.
With set -x, we put our shell into a mode where all executed commands will be printed to standard output as well. Finally, at the end of the script, we turn this debug mode off with set +x.
4. Fail Fast
When it comes to it, nothing gets as good as the real thing. We can mimic everything the cron daemon does, but we can only make sure our job works as expected by running it through the job itself.
We can set our cron expression to a very near time in the future and log everything to a file:
42 20 * * * /path/to/cronjob.sh > /tmp/cronjob.log 2>&1
Our script will be executed at 20:42. We capture everything in a log file by redirecting standard error to standard out by using 2>&1.
In this article, we learned how to test cron jobs. We learned that they run in a limited environment and how we can deal with that.
We also took some additional measures by adding logging that will make them easier to debug.