CronJob not running

WTF?! My cronjob doesn't run?!

Here's a checklist guide to debug not running cronjobs:

  1. Is the Cron daemon running?
  • Run ps ax | grep cron and look for cron.
  • Debian: service cron start or service cron restart
  1. Is cron working?
  • * * * * * /bin/echo "cron works" >> /tmp/file
  • Syntax correct? See below.
  • You obviously need to have write access to the file you are redirecting the output to. A unique file name in /tmp which does not currently exist should always be writable.
  • Probably also add 2>&1 to include standard error as well as standard output, or separately output standard error to another file with 2>>/tmp/errors
  1. Is the command working standalone?
  • Check if the script has an error, by doing a dry run on the CLI
  • When testing your command, test as the user whose crontab you are editing, which might not be your login or root
  1. Can cron run your job?
  • Check /var/log/cron.log or /var/log/messages for errors.
  • Ubuntu: grep CRON /var/log/syslog
  • Redhat: /var/log/cron
  1. Check permissions
  • Set executable flag on the command: chmod +x /var/www/app/cron/do-stuff.php
  • If you redirect the output of your command to a file, verify you have permission to write to that file/directory
  1. Check paths
  • Check she-bangs / hashbangs line
  • Do not rely on environment variables like PATH, as their value will likely not be the same under cron as under an interactive session. See How to get CRON to call in the correct PATHs
  1. Don't suppress output while debugging
  • Commonly used is this suppression: 30 1 * * * command > /dev/null 2>&1
  • Re-enable the standard output or standard error message output by removing >/dev/null 2>&1 altogether; or perhaps redirect to a file in a location where you have write access: >>cron.out 2>&1 will append standard output and standard error to cron.out in the invoking user's home directory.
  • If you don't redirect output from a cron job, the daemon will try to send you any output or error messages by email. Check your inbox (maybe simply more $MAIL if you don't have a mail client). If mail is not available, maybe check for a file named dead.letter in your home directory, or system log entries saying that the output was discarded. Especially in the latter case, probably edit the job to add redirection to a file, then wait for the job to run, and examine the log file for error messages or other useful feedback.
  • If you are trying to figure out why something failed, the error messages will be visible in this file. Read it and understand it.

Still not working? Yikes!

  1. Raise the cron debug level
  • Debian
    • in /etc/default/cron
    • set EXTRA_OPTS="-L 2"
    • service cron restart
    • tail -f /var/log/syslog to see the scripts executed
  • Ubuntu
    • in /etc/rsyslog.d/50-default.conf
    • add or comment out line cron.* /var/log/cron.log
    • reload logger sudo /etc/init.d/rsyslog restart
    • re-run cron
    • open /var/log/cron.log and look for detailed error output
  • Reminder: deactivate log level, when you are done with debugging
  1. Run cron and check log files again

Cronjob Syntax

# Minute  Hour  Day of Month      Month         Day of Week    User Command    
# (0-59) (0-23)   (1-31)    (1-12 or Jan-Dec) (0-6 or Sun-Sat)  
         
    0       2       *             *                *          root /usr/bin/find

This syntax is only correct for the root user. Regular user crontab syntax doesn't have the User field (regular users aren't allowed to run code as any other user);

# Minute  Hour  Day of Month      Month         Day of Week    Command    
# (0-59) (0-23)   (1-31)    (1-12 or Jan-Dec) (0-6 or Sun-Sat)  
         
    0       2       *             *                *          /usr/bin/find

Crontab Commands

  1. crontab -l
    • Lists all the user's cron tasks.
  2. crontab -e, for a specific user: crontab -e -u agentsmith
    • Starts edit session of your crontab file.
    • When you exit the editor, the modified crontab is installed automatically.
  3. crontab -r
    • Removes your crontab entry from the cron spooler, but not from crontab file.

I want to add 2 points that I learned:

  1. Cron config files put in /etc/cron.d/ should not contain a dot (.). Otherwise, it won't be read by cron.
  2. If the user running your command is not in /etc/shadow. It won't be allowed to schedule cron.

Refs:

  1. http://manpages.ubuntu.com/manpages/xenial/en/man8/cron.8.html
  2. https://help.ubuntu.com/community/CronHowto

Finally I found the solution. Following is the solution:-

  1. Never use relative path in python scripts to be executed via crontab. I did something like this instead:-

    import os
    import sys
    import time, datetime
    
    CLASS_PATH = '/srv/www/live/mainapp/classes'
    SETTINGS_PATH = '/srv/www/live/foodtrade'
    sys.path.insert(0, CLASS_PATH)
    sys.path.insert(1,SETTINGS_PATH)
    
    import other_py_files
    
  2. Never supress the crontab code instead use mailserver and check the mail for the user. That gives clearer insights of what is going.


Another reason crontab will fail: Special handling of the % character.

From the manual file:

The entire command portion of the line, up to a newline or a
"%" character, will be executed by /bin/sh or by the shell specified
in the SHELL variable of the cronfile.  A "%" character in the
command, unless escaped with a backslash (\), will be changed into
newline characters, and all data after the first % will be sent to
the command as standard input.

In my particular case, I was using date --date="7 days ago" "+%Y-%m-%d" to produce parameters to my script, and it was failing silently. I finally found out what was going on when I checked syslog and saw my command was truncated at the % symbol. You need to escape it like this:

date --date="7 days ago" "+\%Y-\%m-\%d"

See here for more details:

http://www.ducea.com/2008/11/12/using-the-character-in-crontab-entries/