I write a Laravel Command, and it will fork some child process. Child process will update the DB by Eloquent.
Code:
<?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);
}
}
}
Run my code:
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
What's the reason behind that? And How to update the MySQL by Eloquent in child process?
PS:
I think the reason for that problem is, all child processes use the same MySQL connection which forked from the parent process.
If I don't call Item::first()
in the parent process before call fork()
, it works well. (In my real use case, I can't do that... The parent process will do a lot with MySQL before fork child process.)
Because in that case, the MySQL connection doesn't initialize in the parent process, so every child process will initialize a connection on their own.
So, if it's the case, how to initialize a new MySQL connection for each child process after forked?
Since it's all about the connection dying, you can solve this by simply reconnecting to the database.
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);
}
}
I tested this in Laravel 5.6 and it works.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With