Я пишу команду Laravel, и она разветвляет некоторый дочерний процесс. Дочерний процесс обновит БД Eloquent.
Код:
<?php
namespace App\Console\Commands;
use App\Console\BaseCommand;
use App\Item;
use Illuminate\Console\Command;
class Test extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'test';
/**
* The console command description.
*
* @var string
*/
protected $description = 'Command description';
/**
* Create a new command instance.
*
* @return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* @return mixed
*/
public function handle()
{
Item::first();
$children = [];
for($i = 0; $i < 5; $i++) {
$pid = pcntl_fork();
if ($pid == -1) {
die('pmap fork error');
} else {
if ($pid) {
$children[] = $pid;
} else {
Item::first(); exit;
}
}
}
foreach ($children as $child) {
pcntl_waitpid($child, $status);
}
}
}
Запустите мой код:
vagrant@homestead:~/ECAME$ php artisan test
[Illuminate\Database\QueryException]
Packets out of order. Expected 1 received 116. Packet size=6255201 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)
[Illuminate\Database\QueryException]
Packets out of order. Expected 1 received 100. Packet size=6238815 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)
[Illuminate\Database\QueryException]
Packets out of order. Expected 1 received 0. Packet size=2816 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)
[Illuminate\Database\QueryException]
Packets out of order. Expected 1 received 116. Packet size=6381412 (SQL: select * from `items` where `items`.`deleted_at` is null limit 1)
[ErrorException]
Packets out of order. Expected 1 received 100. Packet size=6238815
[ErrorException]
Packets out of order. Expected 1 received 116. Packet size=6381412
[ErrorException]
Packets out of order. Expected 1 received 116. Packet size=6255201
[ErrorException]
Packets out of order. Expected 1 received 0. Packet size=2816
В чем причина этого? И как обновить MySQL с помощью Eloquent в дочернем процессе?
PS:
Я думаю, что причина этой проблемы в том, что все дочерние процессы используют одно и то же соединение MySQL, которое разветвляется от родительского процесса.
Если я не вызываю Item::first() в родительском процессе перед вызовом fork(), он работает хорошо. (В моем реальном случае использования я не могу этого сделать ... Родительский процесс будет много делать с MySQL до дочернего процесса fork.)
Потому что в этом случае соединение MySQL не инициализируется в родительском процессе, поэтому каждый дочерний процесс инициализирует соединение самостоятельно.
Итак, если это так, как инициализировать новое соединение MySQL для каждого дочернего процесса после разветвления?
Разветвленные процессы не могут совместно использовать (глобальные) ресурсы. Настоящий вопрос - почему вы разветвляетесь и является ли это реальным решением вашей проблемы? Вы должны устанавливать соединение MySQL в каждом ответвленном запросе.
Привет! Я согласен с предыдущим комментарием ... Я не хочу критиковать ваш подход к процессу разветвления, но действительно ли это только одно решение и действительно ли оно необходимо? ... Мне любопытно - каковы причины, которые подтолкнули вас к выбору это решение? Спасибо!






Поскольку все дело в том, что соединение умирает, вы можете решить эту проблему, просто повторно подключившись к базе данных.
use Illuminate\Support\Facades\DB;
[...]
public function handle()
{
User::first();
$children = [];
for ($i = 0; $i < 5; $i++)
{
$pid = pcntl_fork();
if ($pid == -1)
{
die('pmap fork error');
}
else
{
if ($pid)
{
$children[] = $pid;
}
else
{
DB::connection()->reconnect(); // <----- add this
User::first(); exit;
}
}
}
foreach ($children as $child)
{
pcntl_waitpid($child, $status);
}
}
Я тестировал это в Laravel 5.6, и он работает.
Тогда покажите нам более подходящий код для воспроизведения ошибки.
А если вы определите второй ddbb с такими же параметрами в вашем файле database.php и запустите свой Item :: first на основе второго соединения?
# Primary database connection
'mysql' => [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'myddbb',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
],
# Secondary database connection
'mysql_forConnectChildren' => [
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'myddbb',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
],
Позже
$item = \DB::connection('mysql_forConnectChildren')->select('select * from Item')->get(1);
Я не тестировал, но думаю, может работать
После разветвления процесса в Laravel размещение следующего кода внутри дочернего элемента создало для меня стабильное клиентское соединение mysql в Laravel 4.2:
DB::disconnect();
// we need to clone the database connection of the parent and
// create a new connection as using the original causes protocol errors
$dbconn_child =
[
'driver' => DB::connection()->getConfig('driver'),
'host' => DB::connection()->getConfig('host'),
'port' => DB::connection()->getConfig('port'),
'database' => DB::connection()->getConfig('database'),
'username' => DB::connection()->getConfig('username'),
'password' => DB::connection()->getConfig('password'),
'charset' => DB::connection()->getConfig('charset'),
'collation' => DB::connection()->getConfig('collation'),
'prefix' => DB::connection()->getConfig('prefix'),
'modes' => DB::connection()->getConfig('modes'),
'options' => DB::connection()->getConfig('options'),
];
Config::set('database.connections.DB_CONFIG_CHILD', $dbconn_child);
DB::setDefaultConnection('DB_CONFIG_CHILD');
DB::reconnect();
Это динамически создает новое соединение с теми же параметрами, что и исходное, а затем переключает дочерний процесс на новое соединение и подключается.
Простое отключение и повторное подключение соединения по умолчанию привело к набору ошибок протокола mysql, аналогичных результатам OP.
на самом деле, я обнаружил, что если параметры подключения точно такие же, похоже, что PDO все еще подключает вас к родительскому подключению. Я закончил тем, что изменил параметры параметров и режимов таким образом, чтобы это не повлияло на работу значимым образом, но было отличным от дочернего элемента, что не позволяло PDO выбирать существующее соединение из пула.
эта ссылка может вам помочь laracasts.com/discuss/channels/laravel/…