はじめに
こんにちは。webアプリにつきもののバッチ処理ですが、もちろんLaravelでもサポートされていて、crontabに書き散らすことなくバッチを設定できます。
 今回はLaravelでコンソールやcronから処理を呼び出し、バッチとして実行する方法を紹介します。
環境
- PHP 7.3.3
 - Laravel 5.8.21
 
artisanコマンド作成
以下のコマンドで、Artisanコマンドを自作します。ここで作成するコマンドは
php artisan
でCUIから実行できますし、今回のテーマであるバッチ処理でも呼び出すことができます。
|   1 2  |  $ php artisan make:command TestBatch Console command created successfully.  |  
これで
app/Console/Commands
に
TestBatch.php
が作成されます。
|   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43  |  <?php namespace App\Console\Commands; use Illuminate\Console\Command; use Illuminate\Support\Facades\DB; class TestBatch extends Command {     /**      * The name and signature of the console command.      * artisanコマンドで呼び出す時のコマンド名を定義する      * @var string      */     protected $signature = 'batch:test';     /**      * The console command description.      * artisanコマンド一覧の出力時に表示される説明文、必須ではないが設定推奨      * @var string      */     protected $description = 'お試しのバッチ処理';     /**      * Create a new command instance.      *      * @return void      */     public function __construct()     {         parent::__construct();     }     /**      * Execute the console command.      * 実際の処理をこのメソッド内に記述する      * @return mixed      */     public function handle()     {         DB::table($table)->where('email', '=', 'nomura@example.com')->get();     } }  |  
これでもうartisanコマンドから呼び出せるようになっています。確認してみましょう。
|   1 2 3 4 5 6 7 8 9 10 11 12  |  $ php artisan list Laravel Framework 5.8.21 (中略) Available commands: (中略)  batch   batch:test           お試しのバッチ処理 (中略)  |  
このように表示されればOKです。
php artisan batch:test
をコンソールから実行することで、先ほどの
TestBatch
クラスの
handle
メソッドが呼び出されます。
artisanコマンドをバッチとして登録する
コンソールからartisanコマンドとして呼び出せるようになりました。同じ要領でartisanコマンドを必要なだけ作り、全てcrontabに登録してもよいのですが、バッチが増えるほど煩雑になり、管理しづらくなります。
 Laravel内に全てのコマンドを登録し、見通しよく管理できるようにしましょう。
app/Console/Kernel.php
を編集します。
|   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50  |  <?php namespace App\Console; use App\Console\Commands\TestBatch; use Illuminate\Console\Scheduling\Schedule; use Illuminate\Foundation\Console\Kernel as ConsoleKernel; class Kernel extends ConsoleKernel {     /**      * The Artisan commands provided by your application.      * ここにartisanコマンドクラスを記述する      * @var array      */     protected $commands = [         TestBatch::class,     ];     /**      * Define the application's command schedule.      * artisanコマンドの実行スケジュールを記述する      * @param  \Illuminate\Console\Scheduling\Schedule  $schedule      * @return void      */     protected function schedule(Schedule $schedule)     {         // クロージャに直接処理を書くことも可能         $schedule->call(function () {             echo "hello!\n";         });         // batch:testを毎時実行し、出力先を$filePathに指定する         $schedule->command('batch:test')         ->sendOutputTo($filePath)         ->hourly();     }     /**      * Register the commands for the application.      *      * @return void      */     protected function commands()     {         $this->load(__DIR__.'/Commands');         require base_path('routes/console.php');     } }  |  
上記の
sendOutputTo
や
hourly
以外にも様々な制御が可能です。公式ドキュメントで網羅されていますので、是非見てみてください。
 あとはcrontabに1行追加するだけで、
Kernel.php
に登録したコマンドがそれぞれ実行されるようになります。
|   1 2 3 4 5 6 7 8 9 10 11  |  $ crontab -e # do daily/weekly/monthly maintenance # min   hour    day     month   weekday command */15    *       *       *       *       run-parts /etc/periodic/15min 0       *       *       *       *       run-parts /etc/periodic/hourly 0       2       *       *       *       run-parts /etc/periodic/daily 0       3       *       *       6       run-parts /etc/periodic/weekly 0       5       1       *       *       run-parts /etc/periodic/monthly # 以下1行を追記する *       *       *       *       *       cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1  |  
これで完了です。
 ※ 今回初めてAlpine Linuxのcrontabを触りましたが、Redhat系のcrontabと比べてコメントが親切ですね…
さいごに
以前はcrontabをテキストファイルとしてリポジトリに登録したり、もしくはサーバ上のcrontabを直接編集したりすることが私はほとんどでした。こうやってコード上で管理でき、分かりやすく制御できるのは素晴らしいですね。