のぐそんブログ

暗いおじさんがシコシコ書くブログです。

LaravelでQueueとJobを使ってみる基礎基礎メモ

キューを利用することで、一部の処理を非同期で実行することができます。 以下はユーザー登録する場合にキューを利用した場合のイメージです。

f:id:nogson2:20191218165323p:plain

キューを利用することで、メール送信を待たずに、完了画面を表示することができます。

非同期処理をする

Queueサービス

LaravelにはQueueサービスという非同期を簡単に行うためのサービスが用意されています。
データベースや、Beanstalkd(AWS Elastic Beanstalkとは関係ない)、Amazon SQS、Redisなどにジョブ(非同期処理)を溜め込んでいきます。

f:id:nogson2:20191218172134p:plain

登録されたジョブは、基本的には登録順番に実行されます。
実行されるとドライバー(データベースなど)から削除されます。

Queue用のデータベースを用意する

LaravelではartisanコマンドでQueue用のテーブルを作成することができます。

php artisan queue:table
php artisan migrate

jobsfailed_jobsの2つのテーブルが追加されます。

次に.envを修正します。

QUEUE_CONNECTION=sync
↓
QUEUE_CONNECTION=database

.envに追加。

QUEUE_DRIVER=database

非同期でメールを送信してみる

メールの送信方法は割愛します。
簡単ですが、MailHogを利用してメールを送信する為の メモはこちらにあります。

まずはジョブを作成します。

php artisan make:job SendMail

/app/Jobs配下にファイルが作成されます。
ファイルの中身は以下です。

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class SendMail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

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

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

handleメソッドがジョブの実行処理です。
handleに処理を追加していきます。
※Mailファザードを読み込むのを忘れないように

    public function handle()
    {
        Mail::to('sample@example.com')->send(new SampleMail());
    }

メール送信用のコントローラーを作成して、 controllerをにメール送信処理を追加します。

まずコントローラーを作成します。

php artisan make:controller MailController

コントローラーに処理を追加します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Jobs\SendMail;

class MailController extends Controller
{
    //
    public function create(){
        SendMail::dispatch();
        return '送信完了';
    }
}

DBのjobsテーブルを確認するとjobが設定されています。 f:id:nogson2:20191221094633p:plain

このままだと、jobは実行されません。
jobを実行するにはjobを実行するプロセスのWorkerが必要になります。

以下のコマンドでWorkerを起動します。

docker exec -it laradock_workspace_1 /bin/bash
php artisan queue:work // workerを実行

Workerを起動すると、キューにあるjobが実行されます。

[2019-12-21 01:05:21][42] Processing: App\Jobs\SendMail
[2019-12-21 01:05:22][42] Processed:  App\Jobs\SendMail

失敗した場合は、以下のように表示されます。

[2019-12-21 00:52:36][37] Processing: App\Jobs\SendMail
[2019-12-21 00:52:36][37] Failed:     App\Jobs\SendMail

ジョブの実行ログは/storage/logsで確認できます。

jobが完了するとメールが送信されたのを確認できます。

f:id:nogson2:20191221103042p:plain

その他

Jobの実行を遅らせる

delay(日時)でjobを遅延実行することができます。

class MailController extends Controller
{
    public function create(){
        SendMail::dispatch()->delay(now()->addMinutes(5));
        return '送信完了';
    }
}

Jobを1つだけ実行する

--onceオプションをつけてworkerを起動すると、Queueuに溜まっているJobを1つだけ実行します。

php artisan queue:work --once

溜まっているJobをすべて実行する

delayの実行時間になっていないJobを除いて、Queueに溜まっているJobをすべて実行します。

 php artisan queue:work --stop-when-empty

queueの名前を指定して実行する

負荷分散などの為、キュー分けて実行するなどに利用します。

php artisan queue:work --queue=名前

名前の付け方はdispatchのonQueueメソッドで以下のように指定します。

class MailController extends Controller
{
    public function create(){
        SendMail::dispatch()->onQueue('hogehoge');
        return '送信完了';
    }
}

テーブルに追加されたJobには以下のように設定した名前が付きます。
なにも指定しなければdefaultになります。

f:id:nogson2:20191222131223p:plain

同じqueue名のJobをすべて実行する場合は、こんな感じ。

php artisan queue:work --stop-when-empty --queue=hogehoge