Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP infinite while loop blocks other calls to the script

AIM/MOTIVATION

I want to write a service, which should run all the time. But it should not be possible to start the service again while it is already running.

USE CASE

User X opens the page myService.php and starts the service by clicking a button on the page. After that closes the browser. After a while an another user opens the browser and tries to start the service. But the service should be started only one time.

(SEMI) PSEUDO CODE

<?php 

ignore_user_abort(TRUE);
set_time_limit(0);
$sleepTime = 60;

while(1){

    if( serviceAlreadyStarted() ){
        echo "Service has already been started."; 
        exit;
    }

    if( shouldServiceBeStopped() ){
        echo "Service has been stopped."; 
        exit;
    }
    //  DO SOMETHING
    sleep($sleepTime);
}
?>

EXPECTED BEHAVIOUR

On the second call for switching on the service again, the user gets the message immediately.

ACTUAL BEHAVIOUR

The second call of the script gives no response until the first call exited by the second condition shouldServiceBeStopped()

like image 948
Selim Acar Avatar asked Dec 13 '25 22:12

Selim Acar


1 Answers

tldr: Don't let the user enter a second loop, check whether the service is running before they can press a button to enter a loop.

I would store a value in a database or a JSON file (ini file is fine too). Then when the user first loads the page, read the value and see if it's already started. You can then display a message directly to the user that the process has already started, rather than have them press a button to start it and then show them a message. It cuts out a step and makes things easier for the user, it should also solve your issue where the second loop keeps running until the first is stopped.

The problem with this is if your script crashes while it is running it will leave the file marked as open. There's two ways to get around this. The first is your stopService function can force the file to exit, and in your where loop, if it detects this value exit. This requires the user stopping the service though. The second way, and the way I'd recommend, is to record the date/time stamp of the service, and every time the loop starts have it update the date/time in the file. Then in your serviceAlreadyStarted() function you can check to see if the date/time is within a valid period. If it's not you know the script crashed and can display an error message to the user.

UPDATE

I noticed you've added a comment that you pretty much do this already, but the file remains open. Make sure that you are closing the file after reading / setting the value, straight away. It's also possible that your loop is executing so fast that it's opening and closing the file too quickly for a second copy to access it too. If that is the case I'd only allow the loop to open the file every 100 or so loops, that should allow other instances of the program to access the file as well.

like image 199
Styphon Avatar answered Dec 15 '25 13:12

Styphon