Running rake tasks via cron can be frustrating as often it doesn’t work in the way you expect and often won’t give you any clues as to why. Here is the job I use in my crontab to run Rails rake tasks, plus a bunch of things to try while troubleshooting your own.

Run rake task directly from crontab as a one liner

The following job will run every minute and send the output of the tasks to /var/tmp/cron.log.

* * * * * /bin/bash -l -c 'cd /var/www/my-rails-project && RAILS_ENV=production /home/planetroast/.rbenv/shims/bundle exec rake my-rake-task > /var/tmp/cron.log 2>&1'

Troubleshooting: Set the job to run every minute

Setting the cron job’s time incorrectly will introduce red herrings so for the purpose of troubleshooting let’s set it to run every minute. We do this with 5 asterisks before the command.

* * * * * rest-of-your-cron-job-goes-here

Troubleshooting: Use the ‘-l’ flag

The root cause of my tasks failing is often because cron runs in a minimal environment meaning it might not have access to the tools or variables your job needs to run.

We can get around this by using the -l flag which will invoke a full login shell providing access to your path and all settings in your bashrc. Note that when using this flag we must also pass the command in using the -c flag.

Troubleshooting: Absolute path to bundler

One reason my jobs were failing was because cron didn’t have access to bundler so kept raising a bundle: command not found error. This is due to cron running in a minimal environment, you can fix it by getting the full path and using it in your cron job.

user@planetroast:~$ which bundler
/home/planetroast/.rbenv/shims/bundler

Troubleshooting: Use a wrapper script

If your cron job requires multiple command then cramming it all into one line in the crontab isn’t ideal. It can be better to create a bash script where you can write the commands clearly and easily edit them. This also allows you to easily run the script for testing without having to wait for the clock to tick over.

# Set working directory
cd /var/www/my-rails-app || exit 1

# Run the rake task
RAILS_ENV=production /home/planetroast/.rbenv/shims/bundle exec rake my-rake-task
* * * * * /bin/bash /home/planetroast/my-wrapper-script.sh

Troubleshooting: Log the output

If nothing seems to work then make a temporary file /var/tmp/cron.log and set up a simple cron job which echos some text to a temporary file.

* * * * * echo "Hello from crontab" >> /var/tmp/cron.log

Now you can cat /var/tmp/cron.log to make sure that cron is running.

Troubleshooting: Watch for bash and sh

There is a distinction between using /bin/sh and /bin/bash to run your cron jobs. By default cron using /bin/sh to run jobs but you’re probably going to need bash if you’re running rake tasks. I’m not yet sure exactly why this is but it seems to be a common reason that cron jobs fail.

Troubleshooting: Check the syslog

If your cron job is running a script you can check the syslog to ensure it is running:

grep my-script.sh /var/log/syslog