Using flock() in crontab - php

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

Related

Improve prevent php script run twice (with cronjobs)

I'm like to improve script below, or maybe know if exist a better way to rewrite to better results.
I use this on two files cron1.php and cron2.php executed every 5 seconds and need to prevent running twice.
Script execution time depends of filesize, most of the time took around 2 seconds, but for huge files can take 25/30 seconds, for this i need to stop execution.
I'm on right way? Any suggestion to improve?
$fp = fopen("cron.lock", "a+");
if (flock($fp, LOCK_EX | LOCK_NB))
{
echo "task started\n";
// Here is my long script
// Cron run every 5 seconds
sleep(2);
flock($fp, LOCK_UN);
}
else
{
echo "task already running\n";
exit;
}
fclose($fp);
I generally do a file operation like dumping the getmypid in the lock file. So externally I can know which pid has locked it. In some debugging cases, that is helpful.
Finally, unlink the lock file when you are done.

PHP flock does not lock second run of the script

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);

How to find the first cron job process complete or still running?

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
}

Obtain exclusive read/write lock on a file for atomic updates

I want to have a PHP file that is used as a counter. It will a) echo the current value of a txt file, and b) increment that file using an exclusive lock so no other scripts can read or write to it while it's being used.
User A will write and increment this number, while User B requests to read the file. Is it possible that User A can lock this file so no one can read or write to it until User A's write is finished?
I've used flock in the past, but I'm not sure how to get the file to wait until it is available, rather than quitting if it's already been locked
My goal is:
LOCK counter.txt; write to counter.txt;
while at the same time
Read counter.txt; realize it's locked so wait until that lock is finished.
//
$fp = fopen("counter.txt", 'w+');
if(flock($fp, LOCK_EX)) {
fwrite($fp, $counter + 1);
flock($fp, LOCK_UN);
} else {
// try again??
}
fclose($fp);
From documentation: By default, this function will block until the requested lock is acquired
So simply use flock in your reader (LOCK_SH) and writer (LOCK_EX), and it is going to work.
However I highly discourage use of blocking flock without timeout as this means that if something goes wrong then your program is going to hang forever. To avoid this use non-blocking request like this (again, it is in doc):
/* Activate the LOCK_NB option on an LOCK_EX operation */
if(!flock($fp, LOCK_EX | LOCK_NB)) {
echo 'Unable to obtain lock';
}
And wrap it in a for loop, with sleep and break after failed n-tries (or total wait time).
EDIT: You can also look for some examples of usage here. This class is a part of ninja-mutex library in which you may be interested too.

How does LOCK_SH work?

I'm studing the flock mecanism in PHP and I'm having a hard time understanding the functionality of the LOCK_SH mode. I read on a site that it locks the file so that other scripts cannot WRITE in it, but they can READ from it. However the following code didn't seem to work as expected : In file1.php I have:
$fp = fopen('my_file.txt','r');
flock($fp, LOCK_SH);
sleep(20);
flock($fp, LOCK_UN);
And in file2.php I have
$fp = fopen('my_file.txt','a');
fwrite($fp,'test');
I run the first script which locks the file for 20 seconds. With the lock in place, I run file2.php which finishes it's execution instantly and after that, when I opened 'my_file.txt' the string 'test' was appended to it (althought the 'file1.php' was still runing). I try to change 'file2.php' so that it would read from the locked file and it red from it with no problems. So
apparently ... the 'LOCK_SH' seams to do nothing at all. However, if I use LOCK_EX yes, it locks the file, no script can write or read from the file. I'm using Easy PHP and running it under windows 7.
LOCK_SH means SHARED LOCK. Any number of processes MAY HAVE A SHARED
LOCK simultaneously. It is commonly called a reader lock.
LOCK_EX means EXCLUSIVE LOCK. Only a single process may possess an
exclusive lock to a given file at a time.
If the file has been LOCKED with LOCK_SH in another process, flock
with LOCK_SH will SUCCEED. flock with LOCK_EX will BLOCK UNTIL ALL
READER LOCKS HAVE BEEN RELEASED.
http://php.net/manual/en/function.flock.php#78318
flock() implements advisory locking, not mandatory locking. In order for file2.php to be blocked by file1.php's lock, it needs to try to acquire a write (LOCK_EX) lock on the file before writing.
We use LOCK_SH for reading file .
If something writting in this file in this time this type blocking wait finish operation writting and after that unlock and we can read .
If something no writting in this file locked don't set!
<?php ## Модель процесса-читателя
$file = "file.txt";
// Вначале создаем пустой файл, ЕСЛИ ЕГО ЕЩЕ НЕТ.
// Если же файл существует, это его не разрушит.
fclose(fopen($file, "a+b"));
// Блокируем файл
$f = fopen($file, "r+b") or die("Не могу открыть файл!");
flock($f, LOCK_SH); // ждем, пока не завершится писатель
// В этой точке мы можем быть уверены, что в файл
// никто не пишет
// Все сделано. Снимаем блокировку.
fclose($)

Categories