PHP

Laravel5.7でキューを使って重い処理を非同期で動かす

laravel queue
o_wani
この記事は作成から5年以上経過しているため、内容が古くなっている可能性があります。

データの更新とリアルタイムで時間のかかる重い処理を実行していたために、画面がフリーズしてレスポンスがなくなってしまう問題が発生しました。重い処理のみクーロン(定期実行)を提案しましたが、どうしてもリアルタイムでやりたいとのことでした。

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のキューを利用した非同期処理を行う設定が完了します。

これにより、画面のフリーズや時間のかかる重い処理がバックグラウンドで非同期に処理されることで、ユーザのレスポンスを向上させることが可能となります。

参考になれば幸いです。

STAFF
o_wani
o_wani
スタッフ
大学卒業後、15年間WEB業界で働く。現在はマネジメントに従事していますが、ChatGPTの登場に触発され、このブログを再開。AIをパートナーに、自分で手を動かして実装する楽しさと喜びを再発見中。時代が変わりつつある中でも、陳腐化しない情報発信も目指しています。
記事URLをコピーしました