Создавать и отключать процесс PHP без совместного использования каких-либо db-ресурсов, чтобы ребенок мог выйти? - PullRequest
2 голосов
/ 12 июня 2009

Мне нужен «вечный» процесс, который проходит через таблицу 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, поэтому родительский процесс получает ошибку " Msql Сервер ушел ".

Как мне это решить? Это ошибка дизайна?

Как создать и отсоединить процесс в PHP без совместного использования каких-либо ресурсов БД и т. Д., Чтобы дочерний процесс мог свободно выходить?

(Я попробовал: setsid и снова разветвляться, вызывая работников с 'worker_program &' вместо разветвления в php, но это не работает вообще (странно?). Я использую PDO. Также ребята из php.net говорят, что это не ошибка. Это на osx и php5.3 (и на debian).)

Refs:.

php.net / bug: "Родительский процесс потерял соединение с MySQLi после того, как дочерний процесс пропал"

Update / обходной путь

Итак, я наконец нашел способ справиться с этим. Что работает, так это использование popen для порождения рабочих процессов. Таким образом, кажется, что создается совершенно «свежий» процесс без каких-либо акций. Затем я позволяю ребенку разветвляться и отсоединяться. Так в мастер-процессе вместо pcntl_fork или exec:

$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 ]

2 голосов
/ 12 июня 2009

Как насчет использования постоянного подключения 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 голос
/ 12 июня 2009

Как насчет того, если вы явно сбросили дескриптор db, когда выполнялись в потомке, чтобы он не был закрыт при выходе из потомка? Родитель должен сохранить ссылку на свой дескриптор, поэтому ссылка не может быть закрыта.

0 голосов
/ 01 мая 2011

Никто из них не работал для меня. Я сделал это:

// 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 &');
}
...