Laravel5.7でキューを使って重い処理を非同期で動かす
データの更新とリアルタイムで時間のかかる重い処理を実行していたために、画面がフリーズしてレスポンスがなくなってしまう問題が発生しました。重い処理のみクーロン(定期実行)を提案しましたが、どうしてもリアルタイムでやりたいとのことでした。
PHPのフレームワークとしてLaravelを使っているため、その要望を解決するもっと便利なものがあるかもと思い、調べてみました。そして、「Laravelのキュー」という仕組みを見つけました。
キューは、裏で時間を費やす処理を非同期で実行してくれる仕組みです。以下に設定方法を示します。
1.設定
テーブル準備
キューのジョブテーブルとキューが失敗した時用のテーブルを作成します。
$ php artisan queue:table
$ php artisan queue:failed-table
$ php artisan migrate
envファイル修正
QUEUE_CONNECTION=database
2.ジョブの作成
ジョブ作成コマンド実行。キューに投入するジョブを作成します。ジョブが実行される処理の本体です。
$ php artisan make:job UpdateProject
これにより、app/Jobsにクラスが作成されます。以下にサンプルコードを示します。
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\Services\Project\RegisterService;
class UpdateProject implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $timeout = 0;//0秒
public function __construct()
{
//
}
public function handle()
{
$register = new RegisterService();
$projects = $register->getProjects();
//対象をアップデート
if(isset($projects) && count($projects) > 0){
//UPDATE
foreach($projects as $project){
$register->update_trigger($project);
}
}
}
public function failed(Exception $exception)
{
// 失敗の通知をユーザーへ送るなど…
}
}
ジョブがキューに投入されるタイミングを決めて、ジョブが実行されるトリガーを設置する。今回は、データの更新された後に実行されるようにしたいので、Controller側に記述します。
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
.....
.....
.....
try {
.....
.....
//更新処理
UpdateProject::dispatch();
.....
.....
} catch (Exception $e) {
.....
.....
}
}
3.キューワーカの起動
状況に応じて、①または②の方法で。
①ローカル環境の場合
$ php artisan queue:work --sleep=3 --tries=3
キューを受け付ける状態にしておきます。 そして、ジョブの最大実行回数3回、新しく処理するジョブが存在しない時は、3秒でスリープとします。
動作確認
$ php artisan queue:work --sleep=3 --tries=3
[2019-01-31 17:17:52][1] Processing: App\Jobs\UpdateProject
[2019-01-31 17:17:53][1] Processed: App\Jobs\UpdateProject
[2019-01-31 17:19:11][2] Processing: App\Jobs\UpdateProject
[2019-01-31 17:19:11][2] Processed: App\Jobs\UpdateProject
②本番環境の場合
常時稼働するような本番環境では、キューワーカを永続的に実行させるために、Supervisor設定をします。
バックグランドでqueue:workプロセスを永続的に実行し続けるには、キューワーカが止まらずに実行し続けていることを確実にするため、Supervisorのようなプロセスモニタを利用する必要があります。
Supervisor設定
supervisorをインストールします。
$ sudo easy_install supervisor
$ sudo yum install supervisor
設定をします。
$ sudo vim /etc/supervisord.conf
内容は下記のようにする。(command/user/stdout_logfile部分は、環境に合わせる)
[program:laravel-worker]
command=php /vagrant/www/artisan queue:work --sleep=3 --tries=3
process_name=%(program_name)s_%(process_num)02d
numprocs=8
priority=999
autostart=true
autorestart=true
startsecs=1
startretries=3
user=nginx
redirect_stderr=true
stdout_logfile=/var/log/worker.log
サービスの起動します。
$ sudo systemctl enable supervisord
$ sudo systemctl restart supervisord
動作確認
stdout_logfileで指定した場所にログが出力されます。
$ tail -f /var/log/worker.log
以上でLaravelのキューを利用した非同期処理を行う設定が完了します。
これにより、画面のフリーズや時間のかかる重い処理がバックグラウンドで非同期に処理されることで、ユーザのレスポンスを向上させることが可能となります。
参考になれば幸いです。