I want an "eternal" process that goes through a MySQL table and spawns child processes. Pseudo code:
while(true)
$rows = SELECT * FROM workers
foreach($rows as $row){
DELETE $row->id
spawn_child($row->id)
}
sleep(5)
}
function spawn_child($id){
$pid = pcntl_fork()
if($pid <0){
//err
}elseif($pid == 0){
//child
exec("worker_program $id");
exit();
}elseif($pid > 0){
//parent
}
}
The problem is that when the child process comes back from the worker_program and exits, it closes the apparently shared mysql-handle, so the parent process gets a "Msql server went away"-error.
How do I solve this? Is it a design fault?
How do I spawn and detach a process in PHP, without sharing any db resources etc, so that the child is free to exit?
(I have tried: setsid and forking again, calling workers with 'worker_program &
' instead of forking in php, but that doesn't seem to work at all (weird?). I'm using PDO. Also the guys over at php.net say this behaviour is not a bug. This is on osx and php5.3 (and debian).)
Refs.:
php.net/bug: "Parent process lost MySQLi connection after child process gone"
Update/workaround
So I've finally found a way to deal with this. What works is to use popen
to spawn the worker processes. That way it seems a completely "fresh" process is created, without any shares. I then let the child do the forking and detaching itself. So in the master process, instead of pcntl_fork
or exec
:
$p = popen("worker_program $arg","r");
sleep(1); //give it time to detach (won't work otherwise. Any other ideas?)
pclose($p);
And then in the worker program:
#!/usr/bin/env php
<?php
//fully detach from parent, as proposed by the 'gurus'
//(Why can't this be done with only one fork?)
if(pcntl_fork()) {
exit();
}
posix_setsid();
if(pcntl_fork()) {
exit();
}
...