Laravelのメールをキュー投入してバックグラウンドで処理する

# はじめに
[前回の記事](ttps://qiita.com/fakefurcoronet/items/17323a2e11d3eb11c445)で2段階認証を実装したわけですが、[公式ドキュメント](https://readouble.com/laravel/9.x/ja/mail.html)にこんな記述がありました。

> 電子メールメッセージの送信はアプリケーションのレスポンス時間に悪影響を与える可能性があるため、多くの開発者はバックグラウンド送信のために電子メールメッセージをキューに投入することを選択します。

というわけで、2段階認証のコードを送信するメールをキュー投入してバックグラウンドで処理できるようにしたいと思います。

# databaseキュードライバの設定
今回、キュードライバはDBを選択します。
[公式ドキュメント](https://readouble.com/laravel/9.x/ja/queues.html)に従い、ジョブを保存するためのテーブルを追加します。

```console
php artisan queue:table
```
```console
php artisan migrate
```

`.env`ファイルでdatabaseキュードライバを指定します。

```config:.env
...

QUEUE_CONNECTION=database
```

# Mailableクラスの更新
`Mail::to`に対して`queue`メソッドを追加しても良いのですが、
今回はデフォルトでキュー投入するようにしたいため、2段階認証のMailableクラスに対してShouldQueue契約を追加します。

## 変更前
```php:app/Mail/TwoFactorAuthenticationPasswordMail.php
<?php

namespace App\Mail;
...

class TwoFactorAuthPasswordMail extends Mailable
{
    use Queueable, SerializesModels;

    ...
}
```

## 変更後
```php:app/Mail/TwoFactorAuthenticationPasswordMail.php
<?php

namespace App\Mail;
...

class TwoFactorAuthPasswordMail extends Mailable implements ShouldQueue
{
    use Queueable, SerializesModels;

    ...
}
```

これだけで、メール送信のジョブがDBに登録されます。

# キューワーカの実行

DBに登録されたジョブを処理するために、下記のコマンドでキューワーカを実行します。

```console
php artisan queue:work
```

コマンド実行で、ジョブに溜まったメールが随時送信されることを確認できたかと思います。

しかしこのワーカはターミナルを閉じると停止してしまうので、バックグラウンドで動き続けるように設定してやる必要があります。

# Supervisorの設定
公式ドキュメントに倣い、`queue:work`プロセスをバックグラウンドで永続的に実行し続けるために[Supervisor](http://supervisord.org/introduction.html)を設定します。

## インストール
Supervisorは`dnf`で直接インストールすることができないため、`pip`を利用します。

```console
$ sudo dnf -y install pip
$ pip install supervisor
$ supervisord -v
4.2.5
```

## 設定ファイルの作成
下記コマンドで設定ファイルを出力します。

```console
$ sudo su -
$ echo_supervisord_conf > /etc/supervisord.conf
```

[公式サイト](http://supervisord.org/introduction.html)を参考に値をいじる…わけですが、
私はほとんどこちらの[参考サイト](https://awslagi.com/install-supervisor-on-amazon-linux-2023/)と同じように変更しました。ありがたし！

```config:/etc/supervisord.conf
[unix_http_server]
file=/var/run/supervisor/supervisor.sock   ; ←変更

[supervisord]
logfile=/var/log/supervisor/supervisord.log ; ←変更
pidfile=/var/run/supervisord.pid ; ←変更

[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock ; ←変更

[include] ; ←変更(;が残っていると読み込まれません)
files = /etc/supervisord.d/*.ini ; ←変更
```

## ログとsockファイルのディレクトリ作成

Supervisorの設定ファイルの記述通り、ディレクトリを作成します。

```console
$ mkdir -p /var/log/supervisor/
$ mkdir -p /var/run/supervisor/
```

sockファイルも作成。

```console
$ touch /var/run/supervisor/supervisor.sock
$ chmod 777 /var/run/supervisor/supervisor.sock
```

## サービスへ登録
`systemctl`コマンドで起動や停止ができるように、サービスへ登録します。

```console
$ vi /lib/systemd/system/supervisord.service
```

```config:/lib/systemd/system/supervisord.service
Description=Process Monitoring and Control Daemon
Documentation=http://supervisord.org
After=rc-local.service nss-user-lookup.target

[Service]
Type=forking
ExecStart=/usr/local/bin/supervisord -c /etc/supervisord.conf
ExecStop=/usr/local/bin/supervisorctl shutdown
ExecReload=/usr/local/bin/supervisorctl reload

[Install]
WantedBy=multi-user.target
```

## Laravelキューワーカの設定ファイル作成
続いてLaravelキューワーカを永続化するための設定ファイルを作成します。

```console
$ mkdir -p /etc/supervisord.d/
$ vi /etc/supervisord.d/laravel-worker.ini
```

```config:/etc/supervisord.d/laravel-worker.ini
[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /var/www/html/WEBAPP/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=ec2-user
numprocs=4
redirect_stderr=true
stdout_logfile=/tmp/worker.log
```

## 起動設定
最後にSupervisorの起動確認と、自動起動を設定して完了です。

```console
$ systemctl daemon-reload
$ systemctl start supervisord
$ systemctl enable supervisord
```

# おわりに
これまでも何度かSupervisorにはお世話になっていたのですが、今回初めて最初から設定しました。
意外と手間取りました:joy:

# 参考
https://awslagi.com/install-supervisor-on-amazon-linux-2023/