【Laravel】メールをバックグラウンドで送信するキュー/ジョブを実装する

【Laravel】メールをバックグラウンドで送信するキュー/ジョブを実装する

たとえばメールの一斉送信機能の実装で、「送信ボタンを押してから、遷移先ページの読み込み完了までに時間がかかる……」というケースがあります。ページが開くまで、メール送信処理に時間がかかっているためです。

このケースを解決するには、ページ遷移の方を優先して、裏側(非同期)でメール送信処理を実行してもらいます。

このバックグラウンド処理をLaravelで実現してくれるのが「キュー」です。

キューを使用することで、処理を非同期で実行でき、処理の遅延やサーバーの負荷を軽減できます。

キューのイメージ

Laravelのキューを利用して、メールの一括送信を実装する場合の、おおまかなイメージは以下のとおりです。

  1. (フロント)「メール一括送信」などをクリック
  2. キュー(jobsテーブル)にジョブが保存
  3. (フロント)ページ遷移またはリダイレクト
  4. バックグラウンドでジョブをひとつずつ処理

Laravelでメール一括送信用のキューとジョブを実装する手順

基本的な方法は、公式ドキュメントに沿って進めています。

参考 キュー 8.x Laravel

1. ジョブを保持するためのテーブルを作成

まずはマイグレーションファイルを作成し、そのままマイグレーションを実行します。

php artisan queue:table
php artisan migrate

これで、データベースにjobsというテーブルが作成されます。

2. .envファイル内のQUEUE_CONNECTION変数を設定

.envファイルのQUEUE_CONNECTIONdatabaseにします。

QUEUE_CONNECTION=database

3. ジョブクラスの作成

以下のようなコマンドを打つことで、app/Jobsディレクトリにジョブファイルを作成できます。ジョブ名は任意に決めてください。

php artisan make:job SendNotificationEmail

4. メール送信処理をジョブに記載

handleメソッドに、Mailableクラスなどで作ったメール送信処理を書きます。このhandleメソッドは、キューによってジョブが処理されるときに呼び出されます。

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
use App\Mail\InformationNotification;

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

    protected $address;
    protected $information_text;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($address, $information_text)
    {
        $this->address = $address;
        $this->information_text = $information_text;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // メールの送信処理
        Mail::to($this->address)->send(new InformationNotification($this->information_text));
    }
}

コンストラクタの定義や、プロパティの定義、useでのMailableクラスのインポートも忘れず書き加えましょう。

4. メール送信を実行する場所をジョブのdispatchメソッドに置き換える

コントローラーなどで本来メール送信処理を実行していた箇所を、ジョブのdispatchメソッドに置き換えます。

use App\Jobs\SendNotificationEmail;

class TestController extends Controller
{
    public function update(Request $request) {

        // 省略
        $information_text = "お知らせです。";

        foreach ($users as $user) {
            dispatch(new SendNotificationEmail($user, $information_text));
        }

        // 省略
    }
}

このdispatchが実行されると、先ほど作成したjobsテーブル(キュー)にジョブが蓄積されていきます。

実際に、この段階で処理を実行すると、以下のようにjobsテーブルに入ります。

jobsテーブル(キュー)

しかし、まだメールは送信されていません。このジョブレコードをバックグラウンドでひとつひとつ実行していくイメージになります。

5. キューのジョブを処理してメール送信する

キューに投入されたジョブを処理して、実際にメールを送信するには、以下のコマンドでキューワーカを実行する必要があります。

php artisan queue:work

うまくいくと、以下のようにProcessedとなるはずです。

php artisan queue:work Processed

逆にうまくいかない場合は、Failedとなります。この場合はログなどを見て修正しましょう。

php artisan queue:work Failed

メールが届いているかも確認してみましょう。ちなみに、メールのテスト送信には、「Mailtrap」というサービスがおすすめです。無料でテスト用の受信トレイを利用できます。

関連記事 Mailtrapの使い方(Laravelでの使い方を解説しています)

Mailtrapを使うと、以下のように一斉送信メールが届いているのを確認できました。

Mailtrap 受信トレイ

ジョブを永続的にバックグランド実行するには

なお、本番環境などでキューワーカ(queue:work)をバックグラウンドで永続的に実行(監視)し続けるには、モニタリングツールが必要になります。queue:workはさまざまな原因で停止する可能性があるためです。

LaravelではモニタリンツールとしてSupervisorが推奨されています。詳しくは、「Supervisor設定」を参考にしてください。