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?
2 Answers
Answers 1
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.
Answers 2
And if you define a second ddbb with equal parameters in your database.php , and you launch your Item::first based in the second connection ?
# 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' => '', ],
Later
$item = \DB::connection('mysql_forConnectChildren')->select('select * from Item')->get(1);
I not tested but i think can works
0 comments:
Post a Comment