Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel: How to update the MySQL by Eloquent in child process?

Tags:

php

mysql

laravel

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?

like image 596
Sayakiss Avatar asked Jul 20 '18 08:07

Sayakiss


1 Answers

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.

like image 78
GiamPy Avatar answered Nov 20 '22 09:11

GiamPy