I trying to implmente a simpler version of the code in this answer:
How to detect whether a PHP script is already running?
The problem described here is my EXACT situation. I want to prevent cron from launching the same script if it's already running.
I started with this simple test code:
<?php
$script_name = __FILE__;
$lock_file_name = basename($script_name, ".php") . ".lock";
$fp = fopen($lock_file_name, "c");
if (flock($fp, LOCK_EX)) { // acquire an exclusive lock
//ftruncate($fp, 0); // truncate file
//fwrite($fp, "Write something here\n");
//fflush($fp); // flush output before releasing the lock
flock($fp, LOCK_UN); // release the lock
echo "GOT LOCK\n";
sleep(20);
} else {
echo "Couldn't get the lock!\n";
}
flock($fp, LOCK_UN); // release the lock
fclose($fp);
?>
As I understand it, I launch this code in one console and read the Got Lock. If I launch it in another console the I should get the Coudn't get the lock message. Howver I get the Got Lock message both times.
What am I doing wrong?
The file is only locked for the duration of the script. Once the PHP finishes its activities the script tereminates and then the OS unlocks the file.
Note that your sleep(20) call is coming after you have unlocked the file, so there is no pause when the file is locked. So it sounds like you're in effect calling the single script twice in sequence rather than in parallel.
Solution:
Move the sleep(20) statement to before the lock is removed (actually you unlock twice so simply removing the first unlock does this).
$fp = fopen($lock_file_name, "c");
if (flock($fp, LOCK_EX)) { // acquire an exclusive lock
echo "GOT LOCK\n";
/** this time window allows you to run another parallel script to prove the locking mechanism works **/
sleep(20);
} else {
echo "Couldn't get the lock!\n";
}
flock($fp, LOCK_UN); // release the lock
fclose($fp);
Related
I hvave a cron job that is doing some updates. After completion of that process i need to run another cron job for inserting that updated records into another table.For this I am trying this script.
$output = shell_exec('ps -C php -f');
if (strpos($output, "php do_update.php")===false) {
shell_exec('php insert_process.php');
}
But it is not doing any thing and i am getting ps is not internal / external command.
So how can I find that first cron job execution is completed or not?Once that is executed then i will run the second cron for inserting data. Any holp would be greatly appreciated.
You could use some kind of a lock file.
First file:
at the beginning of the first script create empty file on the disk called lockfile.txt (or any other name)
at the end remove the file from the disk
Second file
check if the file called lockfile.txt exists, if not - run the code
you can use flock on running the do_update.php add a lock to it and in
`insert_process.php` run the process if your previous lock is released
in your do_update.php add this
$fp = fopen("lock.txt", "r+");
if (flock($fp, LOCK_EX)) {
//do your process
flock($fp, LOCK_UN); //release the lock
}
in your insert_process.php add this
$fp = fopen("lock.txt", "r+");
if (flock($fp, LOCK_EX | LOCK_NB)) { // checks for the lock
// do your process
}
I am trying a simple algorithm which says:
File1: (lock.php)
Open a File
Lock the File, so that no other PHP file can read this
Sleep
Release Lock
File2: (lockstatus.php)
Try to open the file.
If not opening
Wait for Lock to release
Else
Read the file
My code implementation:
Lock.php:
<?php
$f = fopen("key",'a');
if (flock($f, LOCK_EX | LOCK_NB)) {
echo "File Locked. For Next 60 Seconds\n";
sleep(60);
var_dump(flock($f, LOCK_UN)); //release lock
echo "lock released";
} else {
echo "blocked";
}
?>
Lockstatus.php
<?php
do {
echo "\n";
$f = fopen("key",'a');
if ($f) {
echo "Readable\n";
fclose ($f);
} else {
echo "Blocked! I am waiting\n";
sleep(10);
}
} while (!$f); //wait until fopen does not work
?>
Problem:
Even, flock is applied, the Lockstatus.php is able to open the file.
Question:
How to block the file reading at Lockstatus.php once it is locked by Lock.php?
The problem is that flock() only provides advisory locking. The other program may completely ignore this and proceed to fopen and fread or whatever else. The key is to use flock in your Lockstatus.php as well after your do the fopen to check if there are existing locks. flock in Lockstatus.php would fail and then you would know there is an existing lock.
This function flock() has different behavior on linux and windows.
Take a deep look at "Notes" on PHP docs. This might be your issue.
flock on PHP Docs
After that, pay attention on r+ parameter, it´s mandatory for reading+locking.
$fp = fopen('/tmp/lock.txt', 'r+');
It wont work with a.
I am using a crontab that executes a PHP file. I want to implement the flock() command to help prevent duplicate crontabs from running at one time. If I have:
* * * * * php /var/www/html/welcome.php
How can i add this flock() command? Thanks!
Try this:
$fh = fopen('mutex.txt','r'); // Any convenient file (MUTual EXclusion)
flock($fh, LOCK_EX); // get exclusive lock. Will block until lock is acquired
// Do your exclusive stuff...
flock($fh, LOCK_UN); // release lock
fclose($fh); // close Mutex file.
For complete your answer and as you use a crontab every minute, you may encounter a problem :
If for any reason, your script lack to finish in 1 minute his job or the script fail somewhere and does not remove the lock (stuck inside a 'while'...), the next crontab will start and stay in your process list until the previous remove his lock, and so on...
A better approach would be :
$fh = fopen('/path/to/mutex.txt', 'r'); //Any convenient file (MUTual EXclusion)
if(!flock($fh, LOCK_EX | LOCK_NB)) //Exit if lock still active
exit(-1);
//Your code here
flock($fh, LOCK_UN); //release lock
fclose($fh); //close Mutex file.
And that will avoid any stack of process php
I have a cache file that is updated every hour or so. The file size ranges from 100KB to 1MB. The way the cache is updated is with the file_put_contents() method.
Only the server writes to the file. However, there is continuous access to the file. The file is accessed by users by a script that performs a one time read through readfile() to echo it to the user.
If the file is being read by the caching script, and the server runs the user reading script, or the other way around, would there be a problem? Or is this handled automatically by PHP>
Basically, you should lock the file while writing or reading. At least, it guarantees that there is no problem. It is the way of good programming!. The example is shown below.
<?php
$fp = fopen("/tmp/lock.txt", "w+");
if (flock($fp, LOCK_EX)) { // do an exclusive lock
fwrite($fp, "Write something here\n");
flock($fp, LOCK_UN); // release the lock
} else {
echo "Couldn't lock the file !";
}
fclose($fp);
?>
More information
I have a script that I want to make sure only one is running, I am doing:
$fp = fopen("lock.txt", "w");
if (flock($fp, LOCK_EX|LOCK_NB)) { // do an exclusive lock
//Processing code
flock($fp, LOCK_UN);
}else{
echo "Could not lock file!";
}
fclose($fp);
The problem is when I start the second script, it just stays there waiting. If I then stop the first script, the second script will then print "Could Not lock this file". Why doesn't the second script just stop immediately and report that message?
If it ran the second script, it would know that the file is locked and should exit. When I watch my processes I can see the second script sat there ... it's just wating.
Thanks.
EDIT: I have just tried a quick and dirty database lock i.e set a running field to -1 and check for it when the script opens. But that doesn't work. I have also tried using sockets as described: here . It seems like the second file won't even run ... Should I even be worried?
$fp = fopen("lock.txt", "w");
$block = 0;
if (flock($fp, LOCK_EX|LOCK_NB, $block)) { // do an exclusive lock
sleep(5);
flock($fp, LOCK_UN);
echo "Could lock file!";
}else{
echo "Could not lock file!";
}
fclose($fp);
works for me. Try adding the 3'rd parameter
Edit:
You may have some session locking problems:
when you call session_start() it will block(put further requests in a waiting state) any other requests to your script until the original script that started the session has finished. To test this, try either accessing with 2 different browsers, or avoid calling session_start() in this script.