PHPフレームワークのベンチマーク一覧の記事を拝見し、
Laravel5が遅いという結果が出てしまいちょっとへこみました。
ま、まぁハロワの早さがフレームワークの優劣じゃないし(震え声
ハロワ程度でもちょっとメモリとか多く使っちゃうだけだし(震え声
などと色々理由を付けて自分の涙を無かったことにしています。
一口に速度といっても2つの指標があって、実行速度と開発速度があって
Laravelは開発速度に重きを置かれているということなので、
こういう差がでちゃうのも仕方ないんじゃないかなーと思っています。
ちなみに、今度日本で初めてLaravelの本が出るらしいですね。ちょっと気になっています。
Laravelエキスパート養成読本[モダンなPHP開発を実現するノウハウ満載!] (Software Design plus)
さて本題に戻って、Laravelでのバッチ開発まわりに関して、
公式ドキュメントを読んでも、どうも的を射なかったのでまとめてみます。
目標
Laravelフレームワークを使用したバッチ処理の開発、cronスケジューリング
主要技術・環境
Laravel5
実装
バッチの実装
まずはバッチクラスの作成をartisan
コマンドにて行います。
$ php artisan make:console TestCommand --command='batchtest' Console command created successfully.
クラス定義が簡単でいつも助かります。
上記コマンドを叩くことで、 TestCommand
というクラスファイルが自動で作成され、batchtest
というコマンドが用意され、 $ php artisan batchtest
で実行できるようになります。
さて、ファイルができる場所ですが
project/app/Console/Commands/TestCommand.php
にできます。
早速、中身を確認してみましょう。
見た通りな感じですが、 fire() がメインの動作関数ですね。
fire()
を編集してみましょう。とりあえず実行確認のechoしてみます。public function fire() { echo 'コニチワ'; }コニチワします。
では実行してみましょう。$ php artisan batchtest exception 'InvalidArgumentException' with message 'Command "batchtest" is not defined.' in ~~~怒られた!
コマンドを登録しないといけないようで。
app/Console/Kernel.php
に、下記の通りコマンドクラス定義を追加する必要があります。
ここまでartisan
コマンドで追加してくれてもいいと思うのだけどなぁ。protected $commands = [ 'AppConsoleCommandsInspireCommand', 'AppConsoleCommandsTestCommand' // 追加 ];
TestCommand
クラスを呼び出すよう定義してbatchtest
コマンドを有効化します。
で、再度実行してみます。$ php artisan batchtest exception 'RuntimeException' with message 'Not enough arguments.' in ~~~怒られた!
getArguments()
がデフォルトでは引数を一つ受けないとエラーを吐くようになっているようです。
引数を取る必要がなければ関数まるごと削除してしまって良いようです。
とりあえず適当な引数をつけて実行してみましょう。$ php artisan batchtest "example" コニチワコニチワ!
引数を受けとりたい
引数を受けて処理を分けるというのも多くあるので、そこまで触ってみます。
そもそも初期設定の下記はどういう意味かというと、protected function getArguments() { return [ ['example', InputArgument::REQUIRED, 'An example argument.'], // 一つの引数を受け取る // ['プログラムで受ける変数名', '必須入力か否か', '引数の説明'] ]; }
getArguments()
の返り値配列の要素数が引数の数。
中の配列が「変数名、必須引数か、引数の説明」となっているので、
初期設定では、「引数を一つ必須入力、受け取ったら変数名を’example’とする」みたいな感じです。デフォルト引数のような使い方をしたい場合は、
InputArgument::REQUIRED
をnull
とすればいいようです。return [ ['lang', null, 'choose language. default="ja"], ];これで、「引数一つ自由入力、受け取ったら変数名を
’lang’
とする」という感じでしょうか。
で、どうやって引数を受け取るかですが、fire()
内で$this->argument('変数名')
で使えるようです。__constract()
内で受け取れないのがちょっと勿体無い感じがしますねぇ。
ということで、処理分けは以下のようにできるようですね。public function fire() { $lang = empty($this->argument('lang')) ? 'ja' : $this->argument('lang'); switch($lang){ case 'ja': echo "コニチワn"; break; case 'us': echo "ハローn"; break; default: ~~動かしてみましょう。
$ php artisan batchtest コニチワ$ php artisan batchtest us ハロー
$ php artisan batchtest hoge สวัสดี
สวัสดี!!
empty()
じゃなくてstrlen()==0
で受けるべきかな?まあ用途によって。cron設定
バッチを作成するたびにサーバにSSHログインしてcronの設定をしないといけないのは面倒ですね。
複数台全てにcrontab設定するのは骨が折れる。
Laravelでは、ソースレベルでコマンド実行のスケジューリングを設定できて素敵です。
crontabに下記を設定します。* * * * * php /path/to/project/artisan schedule:run 1>> /dev/null 2>&1すると、毎分バッチ管理スケジューラを起動して、設定にマッチするものを実行するという感じ。
公式ドキュメントには「これ以上簡単にできません!」との記述が。多分これが一番簡単だと思います。
protected function schedule(Schedule $schedule) { $schedule->command('inspire') ->hourly(); $schedule->command('batchtest')->dailyAt('7:00'); // 追加 }これだけで毎朝7時にコニチワできます。
引数をつけたい場合はcommand('batchtest us')
とすればいいだけですね。
バッチが多くなればなるほど、管理の容易さが感じられそう。結果・考察
毎朝7時にコニチワする定期実行バッチができました。
同じプログラムを複数サーバにデプロイする時は、
サーバのホスト名を見て、バッチサーバでだけ実行するとか、web01だけで実行するなんて事も可能ですね。
PHP処理ならではの細かい設定を入れられて管理のしやすいcron、面白いです。