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

##やりたいこと
メール送信処理を非同期で実行できるようにしたい。
つまり`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 インストール
※`supervisor`と`supervisord`が紛らわしいので注意。

### インストール
`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 をブラウザで管理できる
 - http://192.168.00.00（IP）:9001
- `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

## 非同期でメール送信する
[以前投稿したメール送信処理記事](http://qiita.com/komatzz/items/f6177ed695452e8811b6)のコードを少しだけ変更して、メール送信時にキューを使用するようにする。

```app/Mail/RegisterShipped.php
class RegisterApplied extends Mailable implements ShouldQueue
{
```
と言っても`ShouldQueue`インターフェイスを追加するだけ。

#### 正常にキューを使用しているか確認
1. Supervisor を停止
2. メール送信をする
3. メールが届いていないことを確認
4. Supervisor を起動
5. メールが届いていることを確認

##おまけ
実際には Ansible を使って Redis と Supervisor を導入した。
Supervisor 用の`supervisorctl`という[モジュール](http://docs.ansible.com/ansible/supervisorctl_module.html)が用意されているが、`state`に`reread`を指定できなかったので、`command`モジュールを使用した。

```main.yml
...
- name: reread supervisor
  command: supervisorctl reread
...
```