Page 1 of 1
Counting the number of concurent instances of a script
Posted: Fri Jun 24, 2011 4:22 am
by Noodleyman
Morning Guys,
Thought I would see if anybody here could offer some suggestions on this little "feature" I could do with using.
Firstly, my scenario.
I am writing a script that runs on a Windows server (I will port to nix in the future). The script is a cleanup engine for another project. It sits in an endless loop, with a sleep() function at the end to prevent it from going completly nuts and eating CPU. each journey through the loop the app checks for various conditions in the database, and then acts acordingly. in some cases, simply cleaning up old data, in other instances, it will process large chunks of data etc. I've put in a control record in the DB, if the flag gets set to 1, then the script will exit. giving me a controlled way of ending the engine.
Now, what I really want to do is to be able to limit this script to only allow a single instance running. I've seen functions that will work on NIX servers, but not windows. Does anybody know of any way to achieve this?
My current solution is as follows:
When server starts it writes a flag to a db table, 1 = active, 0 inactive. IF it is already set to 1, then it will exit. This works great, but I see a potential issue, in that if the Script dies in an uncontrolled manor, it will leave the flag in the DB showing the script is alive, and fail to restart until I manually update the DB. Does anybody have any suggestions how I can make this a little more dynamic?
Thanks,
Re: Counting the number of concurent instances of a script
Posted: Fri Jun 24, 2011 11:29 am
by McInfo
This is just the first thought I had, so there could be a better way.
Create a new table in your database with these columns:
- An auto-increment number which uniquely identifies a script instance
- A time stamp to keep track of when an instance was last active
- A boolean for whether or not an instance terminated gracefully (default false)
When the script starts, query the database for instances that have not terminated and have recently been active. If none are found, the script can continue. Create a new row in the database with the current time. Have the script remember the auto-increment number. Every X number of times through the loop, update the time. After the loop, which can be broken by your control flag, set "gracefully terminated" to true so the next instance will not have to wait.
Re: Counting the number of concurent instances of a script
Posted: Fri Jun 24, 2011 4:10 pm
by pickle
Another option is to put this maintenance script into a scheduled task (that's the Windows equivalent to cron right?)
Re: Counting the number of concurent instances of a script
Posted: Sat Jun 25, 2011 8:33 am
by jarofgreen
Scheduled tasks only works if you want to run it on a regular interval, not run continuously like a deamon.
The "windows way" is to turn it into a windows service, but to do that the process needs to be able to respond to the special signals windows service manager sends. I've seen commercial products that do this, I have one bookmarked at work, but none free.
Interesting idea, McInfo - I may explore something like that myself. Thanks!
Re: Counting the number of concurent instances of a script
Posted: Sat Jun 25, 2011 10:52 am
by Weirdan
On unix systems this is usually done by creating pid file in a well known location (like /var/run/<script>.pid) and locking it. While the process is running obtained lock would prevent other instances of this script from locking the file, thus notifying them there's already script running. When the process exits (for whatever reason) the lock is dropped and another script may overwrite the file. It's also customary to remove pid file on clean exit.
For windows, if you're ok with 'windows service path', there's extension in PECL called win32service:
http://pecl.php.net/win32service
Re: Counting the number of concurent instances of a script
Posted: Sat Jun 25, 2011 2:15 pm
by jarofgreen
http://www.php.net/manual/en/win32service.examples.php

Thanks Weirdan
Mind you, the stuff I'm needing this for runs in blocks of much longer than 30 secs but I'll just have to make do.
Re: Counting the number of concurent instances of a script
Posted: Mon Jun 27, 2011 8:21 am
by Noodleyman
Hi Guys,
Good suggestions
I actually came up with the following solution in the end.
No single job should take more than 10 mins to complete from the script. Depending on workload, the script could take anywhere between 5 seconds, and 5 hours to complete. I like to know everything that is going on in my script, what it is currently processing etc. So, I have a fairly detailed database table that holds an audit trail, and also a "heartbeat" table. After every action my script performs, it writes an audit entry, and then updates the heartbeat table, with a timestamp, Using time() ). The heartbeat record (single record) links to the ID of the audit record too.
I've now scheduled a task to kick off the script every 15 mins, it checks the heartbeat table for two values. The first, heartbeat.alive (either 1 or 0). If 1, it assumes the script is running and goes on to check 2.. Check 2 compares current value of time() against the one in the heartbeat.time field. If the difference is more than 1200 (20 mins) it assumes the script isn't running and is safe to continue and runs.
So, if the script has been idle for 20 mins (will never happen) then it will start itself, otherwise it just exits.
I think it is quite a nifty solution, as it means I can easily put a front end on it, to allow for a status page. It shows me what is currently being processed, and how long previous tasks have taken etc.
Only problem is, my audit table gets a little large..... Its currently adding about 28 million records per month.. DOH!
Re: Counting the number of concurent instances of a script
Posted: Mon Jun 27, 2011 8:35 am
by Noodleyman
Thought I could say things more clearly in code! So, here are some snippets. I just modified one of the if statements for this post, it isn't tested and might have some syntax errors, but it gives you the idea. The heartbear table is a table with only a single record, and that record is always updated.
SQL:
Code: Select all
CREATE TABLE IF NOT EXISTS `ns_heartbeat` (
`id` int(1) NOT NULL DEFAULT '1',
`isalive` int(1) NOT NULL DEFAULT '0',
`currentlyprocessing` int(11) NOT NULL,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`timestampunix` int(30) NOT NULL,
`endserver` int(1) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
INSERT INTO `ns_heartbeat` (`id`, `isalive`, `currentlyprocessing`, `timestamp`, `timestampunix`, `endserver`) VALUES
(1, 0, 0, '2011-06-26 08:26:50', 1309073180, 0);
PHP:
Code: Select all
// **** A VAR!
$timeout = 1200;
// **** Check if already active
$sql = "SELECT isalive, timestampunix FROM ns_heartbeat";
$query = mysql_query($sql)
or die(mysql_error());
$alive = mysql_result($query,0);
$tsNIX = mysql_result($query,1);
IF($alive == 1 && $tsNIX > (time() - $timeout)){
// **** Write an audit record to show we couldn't start
$AuditS = "NoodleServ Startup - Unable to start because NS_HEARTBEAT.isalive = 1 so I think NoodleServ is already active. Startup Terminated";
auditRecord($AuditS);
echo $AuditS;
// **** End
exit;
}ELSE{
// **** Mark as active
$sql = "UPDATE ns_heartbeat SET isalive = 1";
$query = mysql_query($sql)
or die(mysql_error());
// **** Write an audit record to show we are alive
$AuditS = "NoodleServ Startup - SERVER IS NOW ALIVE";
auditRecord($AuditS);
}
Re: Counting the number of concurent instances of a script
Posted: Mon Jun 27, 2011 11:36 am
by McInfo
It looks good.