Edited at

CakePHP3 で 重いシェルを分割実行する

More than 1 year has passed since last update.


PHPでバッチ処理は辛い

PHP7でどうかは未検証ですが、5系の場合は数万件回すとメモリを

使いすぎだいだい落ちてしまいます。

モデル側にロジックがある場合でやむなく数万件回したい場合によく使用する方法です。

サブループが終了すればメモリは都度開放されるため、

瞬間的なメモリ使用量を減らす事ができます。


メインのループからサブループを呼び出して処理する

<?php

namespace App\Shell;

use Cake\Console\Shell;
use Cake\ORM\TableRegistry;
use Cake\ORM\Table;

/**
* Heavy shell command.
*/

class HeavyShell extends Shell
{

/**
* Manage the available sub-commands along with their arguments and help
*
* @see http://book.cakephp.org/3.0/en/console-and-shells.html#configuring-options-and-generating-help
*
* @return \Cake\Console\ConsoleOptionParser
*/

public function getOptionParser()
{
$parser = parent::getOptionParser();

return $parser;
}
private $select = ["Users.id","Users.name"];
private $where = ["Users.id >" => 0];
Private $limit = 500; //ここの値はサーバーのメモリと相談する
/**
* main() method.
*
* @return bool|int|null Success or error code.
*/

public function main()
{
$limit = $this->limit;
$where = $this->where;
$usersTable = TableRegistry::get('Users');
$total = $usersTable
->find("all")
->where($where)
->count();

$loop = $total / $limit;

for($page = 1 ; $page <= $loop;$page++){
exec( ROOT . DS . "bin" . DS . "cake heavy sub " . $page);
}
}

public function sub($page){
$limit = $this->limit;
$where = $this->where;
$usersTable = TableRegistry::get('Users');

$users = $usersTable
->find("all")
->where($where)
->limit($limit)
->page($page);

foreach($users as $user ){
//なんかの処理
$user->name = "bat de save" . $user->name;
}
$usersTable->saveMany($users);

}

}