LoginSignup
13
20

More than 5 years have passed since last update.

Laravelの処理をQueueにスタックしてレスポンスのチューニングを行おう

Last updated at Posted at 2017-09-08

はじめに

ビジネスロジックを記述する上で処理の高速化は命題です。
が、それにも限界はあります。ではどうすればいいのか?見た目上でも早くなればいいのに。
画面上の操作はトリガに留めて、メイン処理はバックグラウンドで処理すればいいじゃない!
ということでQueueにぶっ込んで非同期的に処理を実行する方法を調べてみました!

やりたいこと

データベース上にキューをスタックするテーブルを作り、画面操作をトリガとしてスタックする。
スタックしたデータは一定時間経過後に実行する。
非同期的に処理を行いたい。
スクリーンショット 2017-09-09 1.25.07.png
最終的には*の部分はajax通信で処理状態を取得できるようにし、Web画面の状況を更新していくようにしたいが・・・。

Queueの実行について

実装に移る前に、以下の設定を行う必要があります。

  • config/queue.php
  • .env
  • database(migration file)

config/queue.php

config/queue.php
return [
    'default' => env('QUEUE_DRIVER', 'database' /* ここを書き換える */),

    'connections' => [
        'sync' => [
            'driver' => 'sync',
        ],
        'database' => [
            'driver'     => 'database',
            'table'      => 'jobs',
            'queue'      => 'default',
            'expire'     => 60,
        ],
        // and more...
    ],
    'failed' => [
        'database' => env('DB_CONNECTION', 'mysql_laravel'),
        'table'    => 'failed_jobs',
    ],
];

それぞれの説明

name discryption
sync 設定していない場合の標準。その名の通り同期的に処理を行うため、Queue最大の恩恵である非同期処理は行えない。
database データベースをジョブキューとして代用する。非同期処理が行えるようになるが事前のマイグレーションが必須。
beanstalkd こういうの。詳しくはググってね。
sqs, iron お金かかるっぽいのでパス。ググ(ry
redis インメモリDB的なやつ。名前は聞くけど詳しいことは知らない。インメモリDBの欠点である揮発性を克服して高速に処理できるっぽい。かがくの ちからって すげー!

とりあえずsyncでテストした後にdatabaseで実装するという段取りで試してみた。

.env

.env
# ...

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=sample_db
DB_USERNAME=homestead
DB_PASSWORD=secret

CACHE_DRIVER=file
SESSION_DRIVER=file
# ここを sync->database に書き換える
QUEUE_DRIVER=database

# ...

ここのQUEUE_DRIVERの値をsyncからdatabaseに書き換える。
実はここでめちゃくちゃハマりました。
Laravel名物、envファイルに泣かされるってやつです。
configファイルいじっても改善されない・・・あるある。

migration

マイグレーションは簡単で、コンソールから次のコマンドを打つだけ。

console
$ php artisan queue:table
$ php artisan queue:failed-table
$ php artisan migrate

Queueファイル作成

次にコンソールからジョブを作っていきます。

console
$ php artisan make:job SampleJob --queued

ここでは超簡単なジョブ、「投入された時間と実行された時間をログに吐く」というサンプルアプリケーションを作ってみて実際に動かしてみます。

app/Jobs/SampleJob.php
namespace App\Jobs;

use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;

class SampleJob extends Job implements SelfHandling, ShouldQueue
{
    use InteractsWithQueue, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $queued_at = date('Y-m-d H:i:s');
        sleep(5);
        $dispatched_at = date('Y-m-d H:i:s');
        \Log::info("処理開始 - {$queued_at} ... 処理終了 - {$dispatched_at}");
    }
}

 なお、トリガは次のようにしてみました。

app/routes.php
Route::get('/queue', function() {
    Queue::push(new \App\Jobs\SampleJob());
    return 'At ' . date('Y-m-d H:i:s') . ' - queue pushed.';
});

実行

早速ブラウザからhttp\://192.168.10.10/queueに接続してみると・・・。
スクリーンショット 2017-09-09 0.55.19.png
こんな画面になるはずです。

ついでにMySQLの中身を見てみると・・・。
スクリーンショット 2017-09-09 0.55.39.png
こんな感じになってます。

しかし、今の段階ではQueueにスタックされているだけで、ジョブの実行はされていません。いつまで待ってもされません。
とりあえずartisanから次のコマンドを叩いてJobを実行してみる。

console
$ php artisan queue:work

これで処理が実行されてます。
試しにstorage/logsの中身を見てみると、

[2017-09-09 00:58:19] local.INFO: 処理開始 - 2017-09-09 00:58:14 ... 処理終了 - 2017-09-09 00:58:19

というようにちゃんとログが吐き出されていることと思います。

所感

かなりハマったけど、分かればなんということはないところで引っかかっているというのはもはやいつものこと。
とりあえずキューが使える環境は整ったので、今後はドキュメント読みながら組み上げていきたいですね。
最終的にはコマンドと組み合わせてバッチ処理を作りたいなぁ。

参考

13
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
20