Edited at

Laravel で Redis と Supervisor を使ってメール送信を非同期にする

More than 1 year has passed since last update.


やりたいこと

メール送信処理を非同期で実行できるようにしたい。

つまりphp artisan queue:workがバックグラウンドで実行されている状態を目指す。

そのためにはキャッシュサーバーと、上記コマンドがバックグラウンドで実行できる環境が必要。

なので、Redis(キャッシュサーバー)と Supervisor(上述コマンドがバックグラウンドで実行できる環境)を導入する。

※Queue サービスが SQS とかになってもこの手順は変わらないはず。


環境


  • CentOS 7

  • PHP 7

  • Laravel 5.3


Redis インストール


インストール

sudo yum --enablerepo=remi,remi-test,epel install redis


起動

sudo systemctl start redis


起動確認

redis-cli ping


PONG


と表示されればOK


Redis クライアントライブラリインストール


設定周り変更


.env

QUEUE_DRIVER=redis



config/queue.php

'default' => env('QUEUE_DRIVER', 'redis'),



composer.json

"predis/predis": "~1.0"



Jobを作成する

php artisan make:job SampleJob


->Job created successfully.



確認用に適当な出力を書く


app/Jobs/SampleJob.php

public function handle()

{
echo 123;
}


Queue に登録する


SampleController.php

  dispatch(new \App\Jobs\SampleJob());



Queue リスナー起動

php artisan queue:listen


123


と表示されればOK


Supervisor インストール

supervisorsupervisordが紛らわしいので注意。


インストール

sudo yum install supervisor


バージョン確認

rpm -qa | grep supervisor


supervisord 起動

sudo systemctl start supervisord.service


起動確認

sudo systemctl status supervisord.service


自動起動にする

sudo systemctl enable supervisord.service


設定ファイル編集

必要最低限の部分だけ編集する。

そもそもこの場所に無いかもしれないので注意。


/etc/supervisord.conf

[inet_http_server]  ; inet (TCP) server disabled by default

port=0.0.0.0:9001 ; (ip_address:port specifier, *:port for all iface)
username=user ; (default is no username (open server))
password=123 ; (default is no password (open server))

[program:worker]
command=php artisan queue:work redis --tries=1 --sleep=3 ; the program (relative uses PATH, can take args)
process_name=%(program_name)s_%(process_num)02d ; process_name expr (default %(program_name)s)
numprocs=2 ; number of processes copies to start (def 1)
directory=/home/projectname ; directory to cwd to before exec (def no cwd)
autostart=true ; start at supervisord start (default: true)
autorestart=true ; retstart at unexpected quit (default: true)
user=root ; setuid to this UNIX account to run the program
redirect_stderr=true ; redirect proc stderr to stdout (default false)
stdout_logfile=/home/projectname/storage/logs/worker.log ; stdout log path, NONE for none; default AUTO



設定ファイル編集の Tips



  • [inet_http_server]の欄をアンコメントすれば Supervisor をブラウザで管理できる




  • numprocs=はサーバーのコア数と同じにするのが一般的


  • directory=はフルパスにしないと正常に動作しない


supervisord 再起動

sudo systemctl restart supervisord.service


config の再読み込み

sudo supervisorctl reread

reloadではないので注意


設定の反映

sudo supervisorctl update


サービス(ワーカー)起動

sudo supervisorctl start worker:*


確認

sudo supervisorctl status


worker:worker_00 RUNNING pid 667, uptime 2:40:00


のように表示されればOK


ログの場所


  • ワーカー(上述の設定ファイルの記述先)


    • /home/project/storage/logs



  • Supervisor 自体


    • /var/log/supervisor/supervisord.log




非同期でメール送信する

以前投稿したメール送信処理記事のコードを少しだけ変更して、メール送信時にキューを使用するようにする。


app/Mail/RegisterShipped.php

class RegisterApplied extends Mailable implements ShouldQueue

{

と言ってもShouldQueueインターフェイスを追加するだけ。


正常にキューを使用しているか確認


  1. Supervisor を停止

  2. メール送信をする

  3. メールが届いていないことを確認

  4. Supervisor を起動

  5. メールが届いていることを確認


おまけ

実際には Ansible を使って Redis と Supervisor を導入した。

Supervisor 用のsupervisorctlというモジュールが用意されているが、staterereadを指定できなかったので、commandモジュールを使用した。


main.yml

...

- name: reread supervisor
command: supervisorctl reread
...