Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

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.

share|improve this question
    
This would be a good question for Unix SE –  xenoterracide Nov 9 '10 at 13:09

7 Answers 7

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. The existence of the lock file doesn't make a difference -- it uses a flock() system call to lock the file, which is automatically released at process death.

Note, if your script is a shell script, you can use some clever redirection tricks to use flock within your script itself. See the man page.

share|improve this answer

Checking for pid or lock file can fail when the cron job fails to clean the file after exit. I see the better option is to check for the process itself such as:

ps -ef | grep script_name | grep -v grep | wc -l

This will give you the number of processes that have the name 'script_name'. You can check this count at the beginning of your script execution.

share|improve this answer
    
Ok, this solution will work when the script crashes?! –  powtac Nov 9 '10 at 13:22
    
pgrep is less likely to give false positives. Or you could use ps -e -o cmd= | grep "^$scriptname". –  Dennis Williamson Nov 9 '10 at 14:14
    
Better yet is to wrap the first letter of the grep search term in square braces, such as 'ps ax | grep [f]oobar'. The process list will duplicate the braces, but will filter out on the grep as not matching the regex. –  Magellan Jul 2 at 5:47

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"
share|improve this answer
    
+1 Yours is a good approach, but it's still possible (however rare) that the both the pidfile and the PID could exist but not be related. Instead of kill -0 you could do if [ "$(ps -p $PID o cmd=)" = "$scriptname" ] or if [ "$(pgrep "$scriptname")" = "$PID" ]. –  Dennis Williamson Nov 9 '10 at 14:09

You can't, cronjobs don't come with this functionality. Put something in your script to check for it, or have it create a file when finished and use something such as inotifywait to block.

share|improve this answer

Look for a file in e.g. /var/run. If the file is found then exit. Otherwise, create the file, run your routine, and then remove the file.

share|improve this answer

There are many ways. Popular one is to use a lock file.

1) When the script starts, it checks if a lock file (like /var/lock/powtac.loc) already presents.

2) If it does exist, script aborts, assuming the previous script is still running *).

3) If it does not exist, script creates the file and continues to do whatever it needs to do.

4) Upon exit, script deletes the lock file.

*) It would also be possible to check the process list at this point, search for matches for your cron job and if found, see when they were started. If recently, then assume they are still running, if loooooooooong time ago, then assume they were stuck.

share|improve this answer

I wouldn't have two cron jobs I'd have one.

* * * * * /some/command && /some/other/command

It will only run if the first command completes successfully, and only after it's done.

( note: if you need it to be a few minutes after use sleep )

share|improve this answer
    
question implies it's the same task but it sometimes takes longer than the delay to run. Doing it your way, he'd just have your command running every 10 minutes instead of his command twice every 5 minutes. –  James Lawrie Nov 9 '10 at 13:13
    
bagh...then he's just running it too often, imo. I read it wrong... but I'm still leaving my answer. –  xenoterracide Nov 9 '10 at 13:15
    
Not all cronjobs run in deterministic lengths of time, particularly ones like rsyncing from a mirror. –  jgoldschrafe Nov 9 '10 at 13:35
    
@jgoldshrafe and you think rsyncing a mirror every 5 minutes is a good idea? nothing runs in a deterministic length of time, everything is variable –  xenoterracide Nov 9 '10 at 13:37

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.