I have a procedure I need to run which basically is like this:
foreach($records as $record){
//contact another website's API via curl..
//record the information in the database
}
The real problem here is that it takes time to get the reply from the other server - sometimes as much as 60 seconds, which they can't help me with
SO, I started looking into proc_open and some approach to multithreading, and so far I have managed to lock up my server several times and need a reboot from hostgator.. ugh
so my thought was to do as follows. First, here's the code I found on the web:
class Thread {
# from http://www.alternateinterior.com/2007/05/multi-threading-strategies-in-php.html
var $pref ; // process reference
var $pipes; // stdio
var $buffer; // output buffer
/* private */ function Thread() {
$this->pref = 0;
$this->buffer = "";
$this->pipes = (array)NULL;
}
/* public static */ function Create ($file) {
$t = new Thread;
$descriptor = array (
0 => array ("pipe", "r"),
1 => array ("pipe", "w"),
2 => array ("pipe", "w")
);
prn('begin');
$t->pref = proc_open ("php -f $file ", $descriptor, $t->pipes);
print_r($t->pref);
stream_set_blocking ($t->pipes[1], 0);
exit;
return $t;
}
/* public instance */ function isActive () {
$this->buffer .= $this->listen();
$f = stream_get_meta_data ($this->pipes[1]);
return !$f["eof"];
}
/* public instance */ function close () {
$r = proc_close ($this->pref);
$this->pref = NULL;
return $r;
}
/* public instance */ function tell ($thought) {
fwrite ($this->pipes[0], $thought);
}
/* public instance */ function listen () {
$buffer = $this->buffer;
$this->buffer = "";
while ($r = fgets ($this->pipes[1], 1024)) {
$buffer .= $r;
}
return $buffer;
}
/* public instance */ function getError () {
$buffer = "";
while ($r = fgets ($this->pipes[2], 1024)) {
$buffer .= $r;
}
return $buffer;
}
}
and here's my brilliant idea of how to use it (except of course for the fact it doesn't work 🙂
foreach($records as $idx=>$record){
prn('[p] '. date('H:i:s').' processing record '. $idx);
//use your imagination here, we have to do a time intensive process with the record - done in myfile.php
$threadCount=15; //number of processes allowed to run
$processed=false; //we do not have a thread yet
for($i=1; $i<=$threadCount; $i++){
if(!$threads[$i]){
//run the call on this node
$processed=true;
prn(' starting new thread on '.$i);
$threads[$i]=Thread::create('contactAPI.php');
exit;
break;
}else if($threads[$i]->isActive()){
//we cannot use this thread index, it is busy
prn(' thread '.$i.' busy');
continue;
}else{
//close the thread and run the new process
$threads[$i]->close();
$processed=true;
prn(' reusing thread '.$i);
$threads[$i]=Thread::create('contactAPI.php');
break;
}
}
if(!$processed){
//handle overflow somehow, or notify of error etc.
prn( 'unable to process this record index '.$idx);
}
}
I mean, that looks simple, and I think the logic is sound but calling Thread::create seems to create process that hang around long after, AND the file I am calling never does anything - I've tried to ahve it email me when it's called etc. but no dice.
The bottom line is this:
1. I need to be able to somehow call a process with some parameters, which may take a while to run, and have that process run while I loop on to the next process
2. I need to know whether these processes are active so I can avoid setting a million processes in motion and locking the system up.
I'm searching for more but with the server going down it's hard to test this out 🙁
Samuel