生成并分离PHP进程而不共享任何数据库资源,以便子进程可以退出?

时间:2009-06-12 16:40:23

标签: php mysql shell process daemon

我想要一个通过MySQL表并产生子进程的“永恒”进程。伪代码:

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

问题是,当子进程从worker_program返回并退出时,它会关闭显然共享的mysql-handle,因此父进程会得到一个“ Msql服务器消失” - 错误。

我该如何解决这个问题?这是一个设计错误吗?

如何在PHP中生成和分离进程,而不共享任何数据库资源等,以便孩子可以自由退出?

(我已经尝试过:setsid和forking,再次使用'worker_program &'调用工作人员而不是在php中分叉,但这似乎根本不起作用(很奇怪?)。我正在使用PDO。另外在php.net的人说这个行为不是bug。这是在osx和php5.3(以及debian)上。)

参考文献:

php.net/bug:"Parent process lost MySQLi connection after child process gone"

更新/变通方法

所以我终于找到了解决这个问题的方法。有效的方法是使用popen来生成工作进程。这样看起来似乎是一个完全“新鲜”的过程,没有任何共享。然后我让孩子做分叉和分离。因此,在主进程中,而不是pcntl_forkexec

$p = popen("worker_program $arg","r");
sleep(1); //give it time to detach (won't work otherwise. Any other ideas?)
pclose($p);

然后在工人计划中:

#!/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();
}
...

3 个答案:

答案 0 :(得分:2)

如何使用持久的MySQL连接。当你知道自己已经完成时关闭它。

$conn = new mysqli("p:".$dbhost, $dbuser, $dbpass, $dbname);

$conn = new PDO("mysql:host=$dbhost;dbname=$dbname",$dbuser,$dbpass,
    array(PDO::ATTR_PERSISTENT => true));

答案 1 :(得分:1)

如果在子进程中显式取消设置数据库句柄,那么如何在子出口处关闭它?父级应该保留它的句柄链接,因此链接可能不会被关闭。

答案 2 :(得分:0)

这些都不适合我。我这样做了:

// php execl type behaviour, execute and leave ...
// the args may be passed to $command or $args
// ekerner@ekerner.com.au
function execl($command, $args = array())
{
  $command = escapeshellarg($command);
  foreach ($args as $arg)
    $command .= ' ' . escapeshellarg($arg);
  exec($command . ' 2>/dev/null >&- /dev/null &');
}