2

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?

aarelovich
  • 5,140
  • 11
  • 55
  • 106
  • 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, so you sound like you're in effect calling the single script twice in sequence rather than in parallel. Try adding a `sleep(10)` or similar delay function to the PHP script to generate your expected response. – Martin Nov 11 '20 at 17:10
  • Linux is my OS. I literally have a line that says sleep(20). I call the second script while the first has not finished. Or am I using the line in the incorrect spot? – aarelovich Nov 11 '20 at 17:15
  • Sorry I didn't see your `sleep` code there. Have you read the [flock manual page](https://www.php.net/manual/en/function.flock.php) and confirmed that none of the qualifiers there are present in your situation? – Martin Nov 11 '20 at 17:16
  • Your `sleep` is in the wrong place, because you're sleeping *after* you're unlocking the file. – Martin Nov 11 '20 at 17:17
  • I have read the manual page, but I'm not sure about qualifiers. There is NFS multi thread or anything like that if that's what you mean – aarelovich Nov 11 '20 at 17:18
  • In your `if` statement I would suggest you remove the `flock($fp, LOCK_UN);` code. As this happens anyway after the `if` statement finishes. – Martin Nov 11 '20 at 17:20
  • @Martin ahhh yes!! So sorry! That was it! – aarelovich Nov 11 '20 at 17:20
  • @Martin Thanks for the help! Should I delete the question? It's a huge blunder on my part and I don't see how it would help any one. Or would you like to post an answer so I can give you credit? – aarelovich Nov 11 '20 at 17:21
  • Glad you found it, yeah, we all suffer not seeing the wood for the trees, sometimes. I'm happy you found the issue. – Martin Nov 11 '20 at 17:23

1 Answers1

1

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); 
Martin
  • 22,212
  • 11
  • 70
  • 132