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.

I would like to run a cron job. Scheduling it is easy and works.

My problem is that I don't know how to only have one version of itself running at a time.

Any ideas?

G-Man

share|improve this question

5 Answers 5

My apologies to embobo, but I copied his script and modified it to eliminate the race condition that I noted in my comment to his answer:

#!/bin/sh
LOCKDIR=/var/run/myprog.lock
mkdir --mode=700 $LOCKDIR || exit 0
trap "{ rm -rf $LOCKDIR ; exit 0; }" EXIT
# do stuff

Basically, we are counting on the fact that directory creation is atomic, so that only one copy of this script running concurrently can successfully create $LOCKDIR. It's probably best to make sure that $LOCKDIR is on a local drive, not on an NFS disk or a Samba mount, etc.

share|improve this answer

You could use a lock file. Example shell code:

#!/bin/sh
LOCKFILE=/var/run/myprog.pid
[ -f $LOCKFILE ] && exit 0
trap "{ rm -f $LOCKFILE ; exit 0; }" EXIT
echo "$$" > $LOCKFILE
# do stuff

It is important to make sure that the lock file gets removed at any kind of exit (normal or abnormal). That is what the trap command does.

You could make it more sophisticated by doing more if the lock file exists. For example, get the pid from the file and see if it is actually running.

share|improve this answer
    
This solution has a race condition. The problem is that between the existence test (line 3) and the lockfile creation (line 5), a context switch could allow another copy of the script to run, thus allowing two (or more) copies of the script to run concurrently. Although this answer will probably never hit the race condition when run in the context of cron, see my answer for an alternate solution that is not affected by the race condition. –  Steven Monday Oct 14 '10 at 21:04
    
Excellent point. –  Mark Wagner Oct 15 '10 at 15:40

Just have your script touch a file when it starts and delete that file when it completes. Then within the script, you can check for the existence of that file before doing anything.

In pseudocode:

if (!exists(/var/run/filename))
{
    touch /var/run/filename;
    do stuff;
    rm /var/run/filename;
}
share|improve this answer

You can do the above where you create a lock file or directory. I personally open a socket connection to some high port. This ensures that even if the application crashes the socket will be closed. With a lock file the file can continue and your script will not run till you manually remove it.

In my experience this has proven to be more reliable.

share|improve this answer
    
I like this idea! Could you share an example? Specifically, I would be interested in seeing it done in the Bash shell. –  Aaron Copley Oct 18 '10 at 21:55

There is a "lockfile" binary installed on most systems that you can use to avoid getting into the game of bash scripting oneupsmanship. On RHEL/CentOS/Fedora its part of the procmail package.

So you could put something like:
lockfile /var/lock/mycron.lock && /usr/local/bin/mycron && rm -f /var/lock/mycron.lock

There's more options in the man page, you can set it to wait some amount of time, to clean up after itself, etc.

share|improve this answer

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.