Reputation: 3200
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();
}
...
Upvotes: 2
Views: 3205
Reputation: 5848
None of those worked for me. I did this:
// php execl type behaviour, execute and leave ...
// the args may be passed to $command or $args
// [email protected]
function execl($command, $args = array())
{
$command = escapeshellarg($command);
foreach ($args as $arg)
$command .= ' ' . escapeshellarg($arg);
exec($command . ' 2>/dev/null >&- /dev/null &');
}
Upvotes: 0
Reputation: 25237
How about if you unset the db handle explicitly when done in the child, so it won't be closed on child exit? The parent should retain it's handle link, so the link might not be closed.
Upvotes: 1
Reputation: 70031
How about using a persistent MySQL connection. And closing it when you know you're done.
$conn = new mysqli("p:".$dbhost, $dbuser, $dbpass, $dbname);
$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass,
array(PDO::ATTR_PERSISTENT => true));
Upvotes: 2