views:

202

answers:

3

Hi. I'm trying to check if a process is already running by using a temporal file demo.lock:

demo.php:

<?php
    $active=file_exists('demo.lock');
    if ($active)
    {
        echo 'process already running';
    }
    else
    {
        file_put_contents ('demo.lock', 'demo');
        sleep(10);  //do some job
        unlink ('demo.lock');
        echo 'job done';
    }
?>

however it doesn't seem to work: if I open demo.php twice it always shows "job done", maybe because it considers it the same process? is there some way to do it? I also tried with getmypid() with similar results.

Thanks

+2  A: 

Works for me.

Make sure the script can create a file in the directory. Uncomment the "unlink" line and run the script and check if the lock file exists in the directory. If you don't see it then it's a directory permissions issue.

zaf
Seems weird to me that it doesn't work, too. PHP should send in a warning if permissions were wrong, though.
zneak
Have you tried commenting the "unlink" line? (Sorry, this is @Borgtex) @zneak maybe he's not seeing the warnings/errors...
zaf
Permissions are correct and on a single run, the file is created and then deleted, it doesn't seems to be any problem with that. The problem is that when I run this file in a browser and let's say 5 seconds after I call it again in another tab, that second instance, instead of showing the warning message (because the first one is already running and the file is already created) does the whole process again. If I create an exact copy named demo2.php and run one after another, it works as expected; demo waits 10 secs and demo2 instantly shows the warning
Borgtex
It also works when run from two different browsers, maybe I should try to redirect to another page and let the process running in the server with ignore_user_abort(true);
Borgtex
Ah, maybe it's your browser limiting the number of requests to the url. Why don't you time both requests with a timer - if they are both around 10 seconds then we still have problems but if the second request takes around 20 seconds then you ned to investigate your browser and increase one of the browser settings related to network connections (if there is one).
zaf
+2  A: 

Can't be sure about what's wrong with your specific case assuming a "normal, easy" environment because it works for me, but at least you have a race condition in your code. What if you start two processes at the exact same time, and that both find that demo.lock does not exist?

You can use fopen with the x mode to prevent this from happening. The X mode tries to create the file; if it already exists, it fails and generates an E_WARNING error (hence the shut-up operator). Since filesystem operations are atomic on a drive, it is guaranteed that only one process at a time can hold the file.

<?php

$file = @fopen("demo.lock", "x");
if($file === false)
{
    echo "Unable to acquire lock; either this process is already running, or permissions are insufficient to create the required file\n";
    exit;
}

fclose($file); // the fopen call created the file already
sleep(10); // do some job
unlink("demo.lock");
echo "Job's done!\n";

?>

I've tested it here and it seems to work.

zneak
+1 for the atomic test-and-set
oedo
thanks for the suggestion, I see how using fopen adds another level of safety to the checking. However, I still have the same problem; It's like the second instance waits for the first one to end and delete the file to create it again
Borgtex
@Borgtex: then your problem beats me. I cannot see why it fails. :/ Well, at least I hope I've been useful.
zneak
A: 

Well, sending some headers and flushing seems to work for me (not sure why), so now when I load the page shows "Start" and if I hit the refresh button on the browser before completing the process, the warning message:

<?php

$file = @fopen("demo.lock", "x");
if($file === false)
{
    echo "Unable to acquire lock; either this process is already running, or permissions are insufficient to create the required file\n";
    exit;
}

header("HTTP/1.0 200 OK");
ob_start();
echo "Starting";
header('Content-Length: '.ob_get_length(),true);
ob_end_flush();
flush();

fclose($file); // the fopen call created the file already
sleep(10); // do some job
unlink("demo.lock");    
?>

Thanks for all the answers and suggestions so far

Borgtex