3

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

4
  • Do you ignore user abort? Commented May 18, 2015 at 8:53
  • 2
    How are you checking if the service is running? Commented May 18, 2015 at 8:58
  • Yes. Motivation is, it should be possible to start the service using a regular browser with no need to display any response. Just open the url, start the service and close the browser. The service should run until any other event interrupts it. Commented May 18, 2015 at 9:02
  • @Styphon The first answer was for Hanky Panky. :-) Sorry. HOW I CHECK IF THE SERVICE IS RUNNING: I just use an ini file on the file system. There is a flag "isServiceStopped". (For some reason) The ini file is locked by the first call and a shadow ini file is created which is free for writing access by another calls, so that isServiceStopped flag can be set to TRUE. If this is the case, the first call checks if there is a shadow ini file and the flag is set. If yes the first call will be exitted. Commented May 18, 2015 at 9:08

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

@Styphon

I have already tried many possible methods but no success. Consider the code below. I will describe some concrete cases which make no sense for me

CASE 1 file serviceStarted.txt exists. There is no running call. I call the script and get immeadiately the answer " Service has already been started". There is no delay.

CASE 2 serviceStarted.txt does not exist. I call the script. First loop running and file has been created. Using another tab or browser I call the script again. It takes ca. 20 seconds till I get the message that the service is running.

CASE 3 (most interesting one) Like the case #2 but I create/copy serviceShouldBeStopped.txt manually in/into the related folder before 20 seconds are up (just say 4 seconds after the first call). This causes both the first and second loop stop at the same time. Is it not a bit strange?

// Very first check: 
if (is_file("serviceStarted.txt")) {
    echo "<br> Service has already been started.";
} else {
    while (1) {
        // This check is aquivalent to the shouldServiceBeStopped()
        // I copy this txt manually to the folder in order to stopp the first call        
        if (is_file("serviceShouldStopped.txt")) {
            echo "Service stopped.";
            exit;
        }

        // The first call should create this file
        if (!is_file("serviceStarted.txt"))
            file_put_contents("serviceStarted.txt", "any content");


        sleep(60);
    }
}

UPDATE

// This if statement used in second call
   if (isset($_GET['noloop'])) {
        echo "loop should not be executed";
   }
   else {

    while (1) {
        // This check is aquivalent to the shouldServiceBeStopped()
        // I copy this txt manually to the folder in order to stopp the first call
        if (file_exists("serviceShouldStopped.txt")) {
            echo "Service stopped at " . date("H:i:s");
            exit;
        }
        sleep(60);
    }
}

2 Comments

None of that follows my answer. Firstly, I said take the check for whether the service has started out of the loop. Then I said use a variable inside a file, not whether a file exists or not. You should also post this as an update to your question, not as an answer.
Thank you for your answers and hints. I have already did, what you described in your comments. The check takes outside of the loop (see the top of the code) With the example above, I just wanted do simplifiy the behaviour and minimize the code. In my concrete application I use variables inside file. I updated my answer above with a more simplified code. In this case there is no common file which is accessed by the loop and the check. .But the behaviour is the same as I described in CASE 1-3.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.