Page 1 of 1

Way to ensure only one instance of script is running?

Posted: Tue Jan 11, 2005 4:50 pm
by DMcK
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

Posted: Tue Jan 11, 2005 6:43 pm
by kettle_drum
Your best off setting a flag in a database as its is the easiest way to monitor the situation. If not you could always check to see what is running by doing a 'ps' and check the results for the execution of the file.

Posted: Tue Jan 11, 2005 6:52 pm
by feyd
continuing kettle_drum's thought..

provided you are allowed to make system level calls.

Posted: Tue Jan 11, 2005 10:14 pm
by DMcK
Well, it tried seeing what ps does:

Code: Select all

<?php
$x=passthru("ps");
  echo $x;
?>
and got this:

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...
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:

Code: Select all

<?php
$x=passthru("ps -aux");
  echo $x;
?>
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?

Posted: Tue Jan 11, 2005 10:25 pm
by feyd
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.. ;)

Posted: Wed Jan 12, 2005 9:59 am
by ianlandsman
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.

Posted: Wed Jan 12, 2005 10:20 am
by AGISB
ps will show you ALL running processes. You need to narrow it down

Code: Select all

ps -aux |grep scriptname |grep user
|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.

Posted: Wed Jan 12, 2005 10:34 am
by timvw
that is why shared hostes usually have grsec patches :)

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 -ppassword

Posted: Wed Jan 12, 2005 10:39 am
by Weirdan
DMcK wrote: Is my code correct to use ps? If not, I'll use a flag in a database as suggested.
Your 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.

Posted: Wed Jan 12, 2005 5:36 pm
by printf
Hi

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 ) )
	&#123;
		echo 'ERROR: process already running';
		exit ();
	&#125;
	else
	&#123;
		place_holder ();
	&#125;

	/* 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 ()
	&#123;
		$fp = fopen ( HOLD_FILE, 'w' );
		flock ( $fp, LOCK_EX );
		fputs ( $fp, '' );
		fclose ( $fp );
	&#125;
?>

printf