Not running a cron job when the prev run was not finished

How can I block a cron job when the previous run was not finished. Its a cron job which is running every 5 minutes, but sometimes it needs more than 5 minutes to run.

Edit The script which is called, crashes sometimes! So it can not delete lock file.


Use flock(1):

NAME
       flock - manage locks from shell scripts

SYNOPSIS
       flock [options] <file> -c <command>
       flock [options] <directory> -c <command>
       flock [options] <file descriptor number>
[...]

You can have it block or immediately exit. Pre-existence (or absence) of the lock file doesn't make a difference. It creates the file if needed and uses a flock() system call to lock the file. This lock is automatically released at process death.

For example, in cron:

*/5 * * * * /usr/bin/flock /tmp/my.lock /usr/local/bin/myjob

If your jobs don't always finish in 5 minutes, you might consider using --timeout so that your jobs don't queue up:

flock --timeout=300

Or use --nonblock to exit immediately -- it would be similar to --timeout=0

If your script is a shell script, you can use some clever redirection tricks to use flock within your script itself:

(
  flock -n 9 || exit 1
  # ... commands executed under lock ...
) 9>/var/lock/mylockfile            

Or, the manual also suggests making your script recursive by putting this at the top (it uses the script itself as its lock file):

[ "${FLOCKER}" != "$0" ] && exec env FLOCKER="$0" flock -en "$0" "$0" "$@" || :

See the flock(1) man page for more information


Pid files are the way to go, however, much like init scripts don't just give up when they see a pid file, you should check to ensure that the pid in the file still exists.

Something like this would do the trick:

PIDFILE=/var/run/myscript.pid

if [ -e "$PIDFILE" ] ; then
    # our pidfile exists, let's make sure the process is still running though
    PID=`/bin/cat "$PIDFILE"`
    if /bin/kill -0 "$PID" > /dev/null 2>&1 ; then
        # indeed it is, i'm outta here!
        /bin/echo 'The script is still running, forget it!'
        exit 0
    fi
 fi

 # create or update the pidfile
 /bin/echo "$$" > $PIDFILE

 ... do stuff ...

 /bin/rm -f "$PIDFILE"