Way to ensure only one instance of script is running?
Moderator: General Moderators
Way to ensure only one instance of script is running?
Hello,
I have a cron job that calls one of my scripts every 2 minutes. The execution of the script could be short or long.
I want to ensure that a recently called script can detect that a previously called script is still running.
I can think of methods to do this by setting a flag in a file or database. However, I'm hoping to find a solution inherent in PHP so that there isn't any possibility, however remote, of the scripts running concurrently. Is there something in PHP that will do this? Or perhaps a better way than a flag in a file or database.
Thanks,
Doug
I have a cron job that calls one of my scripts every 2 minutes. The execution of the script could be short or long.
I want to ensure that a recently called script can detect that a previously called script is still running.
I can think of methods to do this by setting a flag in a file or database. However, I'm hoping to find a solution inherent in PHP so that there isn't any possibility, however remote, of the scripts running concurrently. Is there something in PHP that will do this? Or perhaps a better way than a flag in a file or database.
Thanks,
Doug
-
kettle_drum
- DevNet Resident
- Posts: 1150
- Joined: Sun Jul 20, 2003 9:25 pm
- Location: West Yorkshire, England
Well, it tried seeing what ps does:
and got this:
There isn't anything about my scripts running (I ran some to make sure).
I'm not using any chatrooms, so I assume that entropychat and melange are someone else's processes on my host. Same with proftpd.
Is my code correct to use ps? If not, I'll use a flag in a database as suggested.
Edit:
I just tried:
and got even more information about processes running on my host...Probably more information on some of the accounts my host is running than I should. But nothing specifically about myscript.php
Thanks,
Doug
P.S. How come the tags aren't formatting my code all nicey nice?
Code: Select all
<?php
$x=passthru("ps");
echo $x;
?>Code: Select all
PID TTY TIME CMD 1335 ? 00:00:04 proftpd 1984 ? 00:00:00 entropychat 1988 ? 00:00:00 melange 29469 ? 00:00:30 httpd 29470 ? 00:00:28 httpd 29471 ? 00:00:29 httpd 29472 ? 00:00:27 httpd 29474 ? 00:00:23 httpd 29476 ? 00:00:29 httpd 29479 ? 00:00:32 httpd 29482 ? 00:00:28 httpd 29484 ? 00:00:28 httpd 29486 ? 00:00:29 httpd 29487 ? 00:00:27 httpd 29497 ? 00:00:28 httpd 29498 ? 00:00:26 httpd 29500 ? 00:00:27 httpd 29501 ? 00:00:28 httpd 29502 ? 00:00:28 httpd 29503 ? 00:00:29 httpd 29504 ? 00:00:25 httpd 29506 ? 00:00:28 httpd 29507 ? 00:00:29 httpd 29509 ? 00:00:30 httpd 29819 ? 00:00:30... and more like this...I'm not using any chatrooms, so I assume that entropychat and melange are someone else's processes on my host. Same with proftpd.
Is my code correct to use ps? If not, I'll use a flag in a database as suggested.
Edit:
I just tried:
Code: Select all
<?php
$x=passthru("ps -aux");
echo $x;
?>Thanks,
Doug
P.S. How come the
Code: Select all
Last edited by DMcK on Tue Jan 11, 2005 10:29 pm, edited 1 time in total.
- feyd
- Neighborhood Spidermoddy
- Posts: 31559
- Joined: Mon Mar 29, 2004 3:24 pm
- Location: Bothell, Washington, USA
I'd say, the database option is probably the safest, and most portable route. Since cron calls this script every 2 minutes, the chances of concurrancy once a database flag is set up is extremely low as is..
Something you may want to think about is if the database is unavailable, for whatever reason, I'd suggest your script assumes that the script is currently being run in another process. Although, depending on your needs, the other direction is preferred, but then you wouldn't be here..
Something you may want to think about is if the database is unavailable, for whatever reason, I'd suggest your script assumes that the script is currently being run in another process. Although, depending on your needs, the other direction is preferred, but then you wouldn't be here..
-
ianlandsman
- Forum Newbie
- Posts: 24
- Joined: Thu Dec 30, 2004 9:50 pm
- Location: New York
I would be somewhat leary of the database solution because if the DB goes down with the flag set to running then your script may not run again. For example your script starts, checks to see if other script is running, if not it sets the flag, db crashes so script can't unset flag.
Now 2 minutes later the script starts again, checks for the flag and the db is back up and responds that the flag is set so this script aborts. Now you'll never be able to unset that flag until you manually go in and unset it.
A couple not well thought out options include A) set a time with the flag so that you can see how long ago it was set and if it's really long ago reset it. I don't like this option though because it sounds like it may be a long running script and you'll have to guess at how long is too long. B) use a lock/flag file. If the file is there then don't run the script, if it isn't then keep going. This should be a bit safer since it no longer depends on the database (especially in a shared host environment). Of course if script crashes the file will not be deleted but you run that risk in all scenerio's.
Now 2 minutes later the script starts again, checks for the flag and the db is back up and responds that the flag is set so this script aborts. Now you'll never be able to unset that flag until you manually go in and unset it.
A couple not well thought out options include A) set a time with the flag so that you can see how long ago it was set and if it's really long ago reset it. I don't like this option though because it sounds like it may be a long running script and you'll have to guess at how long is too long. B) use a lock/flag file. If the file is there then don't run the script, if it isn't then keep going. This should be a bit safer since it no longer depends on the database (especially in a shared host environment). Of course if script crashes the file will not be deleted but you run that risk in all scenerio's.
ps will show you ALL running processes. You need to narrow it down
|grep scriptname gets you all scripts named scriptname
|grep user the one started by user in case you got more users running that script.
However I find it funny that you can actually use ps on a shared hosting environment and see other users. This is a huge hacker backdoor possibility.
Code: Select all
ps -aux |grep scriptname |grep user|grep user the one started by user in case you got more users running that script.
However I find it funny that you can actually use ps on a shared hosting environment and see other users. This is a huge hacker backdoor possibility.
that is why shared hostes usually have grsec patches 
otherwise it's funny to see things like
otherwise it's funny to see things like
Code: Select all
luser 20809 0.0 0.2 2404 1384 pts/54 Ss 17:08 0:00 mysql -u luser -ppasswordYour code is correct but you will not see the script name in the ps unless you run the script from the command line. Obviously your host has configured php as apache module, that's why you don't see the script name when it's run by the web user.DMcK wrote: Is my code correct to use ps? If not, I'll use a flag in a database as suggested.
Hi
I would just use a place_holder!
printf
I would just use a place_holder!
Code: Select all
<?
ignore_user_abort ( 'true' );
set_time_limit ( 0 );
// the file used as a place_holder
define ( 'HOLD_FILE', './hold.txt' );
if ( file_exists ( HOLD_FILE ) )
{
echo 'ERROR: process already running';
exit ();
}
else
{
place_holder ();
}
/* place the code you want to run below this line */
/* place the code you want to run above this line */
unlink ( HOLD_FILE );
function place_holder ()
{
$fp = fopen ( HOLD_FILE, 'w' );
flock ( $fp, LOCK_EX );
fputs ( $fp, '' );
fclose ( $fp );
}
?>printf