我写了一个Laravel Command,它会分叉一些子进程.子进程将通过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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
运行我的代码:
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
Run Code Online (Sandbox Code Playgroud)
这背后的原因是什么?以及如何在子进程中通过Eloquent更新MySQL?
PS:
我认为这个问题的原因是,所有子进程都使用从父进程分叉的相同MySQL连接.
如果我在调用Item::first()之前没有调用父进程fork(),那么它运行良好.(在我的实际用例中,我不能这样做......在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);
}
}
Run Code Online (Sandbox Code Playgroud)
我在Laravel 5.6中测试了这个并且它可以工作.
| 归档时间: |
|
| 查看次数: |
438 次 |
| 最近记录: |