Pcntl_fork и соединение MySQL ушло

У меня есть цикл foreach, который вилки внутри него. После обработки вилки он обращается к базе данных. Я получаю сообщение об ошибке:

SQLSTATE[HY000]: General error: 2006 MySQL server has gone away

Дело в том, что я подключаюсь к базе данных после того, как я разветкил.

Мой вопрос: зачем это происходит?

Если это произойдет, я действительно обращаюсь к базе данных перед форкированием? Будет ли дочерний узел наследовать соединения DB?

(примечание: я могу отправлять код, но он довольно велик, как и все в классах, что может быть причиной того, что я путаю, когда я обращаюсь к БД. Еще одна вещь, которую вы должны знать, это использование ZF. )

Ответы

Ответ 1

(комментарий → ответ на запрос плаката)

Чтение в нем я вижу, что разветвленные дети наследуют их родительское соединение db, и это известная проблема: http://php.net/manual/en/function.pcntl-fork.php#70721

Ответ 3

Кроме того, это не проблема. Это способ, которым был разработан pcntl_fork. Любое расширение (как четко указывается в документации), которое поддерживает его собственные файловые дескрипторы, будет иметь поврежденные дескрипторы, потому что все дочерние родители имеют общие дескрипторы файлов.

Ответ 4

Вы можете избежать закрытия соединения при выходе из вильчатого процесса, если вы удалите разветвленный процесс с помощью SIGKILL.

<?php
$dbh = new PDO('pgsql:host=localhost', $username, $password);
$pid = pcntl_fork();
if($pid == 0){
        register_shutdown_function(function(){
                posix_kill(getmypid(), SIGKILL);
        });
        exit;
}
sleep(1);
$statement = $dbh->query('select 1');
var_dump($statement);

Причиной этого поведения является то, что когда PHP-процесс завершается, PHP отправляется на сервер базы данных "Завершить соединение". Но сокет будет закрыт системой только тогда, когда все ссылки на сокет будут закрыты. Использование SIGKILL помогает избежать отправки команды "Завершить соединение" на сервере базы данных.

Ответ 5

Вам необходимо закрыть соединение MySQL в родительском процессе, а затем создать новое соединение для каждого дочернего процесса.

<?php
$dbh = new PDO('pgsql:host=localhost', $username, $password);
$pid = pcntl_fork();
if(!$pid){
        // make new connection
        $newConnection = new PDO('pgsql:host=localhost', $username, $password);
        // do something in the child process.
        exit;
}else{ 
        // parent node
        $dbh = null; // close PDO connection
}