I’ve seen a lot of examples where a “lock” file is used to keep track of if a PHP script is currently running.
Example:
- script starts
- checks if “/tmp/lockfile” is currently locked
- If it is locked, exit. If not, lock the file and continue
This way, if a long-running script is started up twice, only the first instance will run. Which is great.
However, it seems like the wrong way to go around it. Why don’t we just check if the process is already running like this?
if(exec("ps -C " . basename(__FILE__) . " --no-headers | wc -l") > 1){ echo "Already running."; exit; }
Are there any potential pitfalls to this method? Why do I see the “lock” file workaround so often? It definitely seems more accurate to count the processes with the name we’re looking for….
Advertisement
Answer
Based on comments here and my own observations, I’ve composed a list of pro’s and con’s of both approaches:
flock
method:
pros:
- More compatible across operating systems
- No knowledge of bash required
- More common approach, lots of examples
- Works even with
exec()
disabled - Can use multiple locks in a single file to allow different running “modes” of the same file at the same time
cons:
- It’s not definite. If your lock file is deleted by an external process / user, you could end up with multiple processes. If you’re saving the lock file in the
/tmp
directory, that’s a valid possibility, since everything in this directory is supposed to be “temporary” - Under certain circumstances, when a process dies unexpectedly, the file lock can be transferred to an unrelated process (I didn’t believe this at first, but I found instances of it happening (although rarely) across 200+ unix based systems, in 3 different operating systems)
exec("ps -C...")
method
pros:
- Since you’re actually counting the processes, it will work everytime, regardless of the state of file locks, etc.
cons:
- Only works in linux
- requires “exec” to be enabled
- If you change the name of your script, it could cause double processes (and make sure your script name isn’t hard-coded in the code)
- Assumes that your script only has one running “mode”
EDIT: I ended up using this:
if (exec("pgrep -x " . $scriptName . " -u ". $currentUser . " | wc -l") > 1) { echo $scriptName . " is already running.n"; exit; }
… because ps
doesn’t allow you to filter on the owner of the process in addition to the process name, and I wanted to allow this script to run multiple times if a different user was running it.
EDIT 2:
… So, after having that running for a few days, it’s not perfect either. Somehow, the process started up multiple times on the same machine under the same user. My only guess is that there was some issue (ran out of memory, etc) that caused the pgrep
to return nothing, when it should have returned something.
So that means that NEITHER the flock
method and the counting process methods are 100% reliable. You’ll have to determine what approach will work better for your project.
Ultimately, I’m using another solution that stores the PID of the current task in a “lock” file, that’s not actually locked with flock. Then, when the script starts up, checks if the lock file exists, and if it does, gets the contents (PID of the last time the script started up) Then, it checks if it’s still running, by comparing the /proc/#PID#/cmdline
contents with the name of the script that’s running.