How to prevent the cron job execution, if it is already running

Solution 1:

Advisory locking is made for exactly this purpose.

You can accomplish advisory locking with flock(). Simply apply the function to a previously opened lock file to determine if another script has a lock on it.

$f = fopen('lock', 'w') or die ('Cannot create lock file');
if (flock($f, LOCK_EX | LOCK_NB)) {
    // yay
}

In this case I'm adding LOCK_NB to prevent the next script from waiting until the first has finished. Since you're using cron there will always be a next script.

If the current script prematurely terminates, any file locks will get released by the OS.

Solution 2:

Maybe it is better to not write code if you can configure it:

https://serverfault.com/questions/82857/prevent-duplicate-cron-jobs-running

Solution 3:

flock() worked out great for me - I have a cron job with database requests scheduled every 5 minutes, so not having several running at the same time is crucial. This is what I did:

$filehandle = fopen("lock.txt", "c+");

if (flock($filehandle, LOCK_EX | LOCK_NB)) {
    // code here to start the cron job
   flock($filehandle, LOCK_UN);  // don't forget to release the lock
} else {
    // throw an exception here to stop the next cron job
}

fclose($filehandle);

In case you don't want to kill the next scheduled cron job, but simply pause it till the running one is finished, then just omit the LOCK_NB:

if (flock($filehandle, LOCK_EX)) 

Solution 4:

This is a very common problem with a very simple solution: cronjoblock a simple 8-lines shellscript wrapper applies locking using flock:

https://gist.github.com/coderofsalvation/1102e56d3d4dcbb1e36f

btw. cronjoblock also reverses cron's spammy emailbehaviour: only output something if stuff goes wrong. This is handy in respect to cron's MAILTO variable. The stdout/stderr output will be suppressed (so cron will not send mails) unless the given process has an exitcode > 0