Laravelでキューを使ってみます。
キューです。FIFO。先入れ先出し。バックグラウンドで重たい処理をやらせたいときなどに便利なやつです。Laravelでも当然用意されています。今回そのキューでメール送信機能を実装しようと思います。Laravelのバージョンは5.7を使います。Laravelのキューのドライバーとしては、データベース、Redis、Amazon SQSなどがあるのですが、今回はデータベースのキューを使ってみようと思います。
まずLaravelのプロジェクト作成です。
$ composer create-project --prefer-dist laravel/laravel queue-sample
Valetでアクセスしてみます。
ユーザ登録機能を作って、登録されたらキューを使って登録完了メールを送ってみます。
マイグレーションの前にデータベースを用意して、接続情報を.env
に記述しておきましょう。
$ php artisan make:auth
$ php artisan migrate
画面右上に2つリンクが表示されるようになりました。
今回使うのは登録画面のほうです。
この画面からユーザ登録出来ます。
登録はapp/Http/Controllers/Auth/RegisterController.php
内のcreate()
が呼ばれます。
ここでreturnさせる前にメール送信キューにエンキューすればいいのではと思うわけです。
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
}
その前にメール送信処理のクラスも作ります。
$ php artisan make:mail UserRegistered --markdown=emails.user.registered
<?php
namespace App\Mail;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;
class UserRegistered extends Mailable
{
use Queueable, SerializesModels;
protected $user;
/**
* Create a new message instance.
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->markdown('emails.user.registered')
->subject('ご登録ありがとうございました')
->with(['user' => $this->user]);
}
}
@component('mail::message')
{{ $user->name }} 様
ご登録ありがとうございました。
{{ config('app.name') }}
@endcomponent
これで準備が整いました。
さあここからがキューです。
https://laravel.com/docs/5.7/queues
https://readouble.com/laravel/5.7/ja/queues.html
config/queue.php
でキューの設定をします。
ですが今回はまだデフォルトのままで、.env
でキューのドライバーをデータベースに変更します。
QUEUE_CONNECTION=database
次にキュー用のテーブルを作ります。Artisanコマンドが用意されているので便利です。
ひとつはキューのジョブテーブルで、もうひとつは実行が失敗したジョブのテーブルです。
$ php artisan queue:table
$ php artisan queue:failed-table
$ php artisan migrate
キューで何を処理するかを記述するジョブクラスを作ります。
$ php artisan make:job SendRegisteredMail
作られたジョブクラスはapp/Jobs
以下に配置されます。
SendRegisteredMail.php
にはコンストラクタとhandle()
メソッドが用意されています。
コンストラクタでジョブに必要なデータを渡し、handle()
で実際にやりたい処理を行うという流れです。
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use App\User;
use App\Mail\UserRegistered;
use Illuminate\Support\Facades\Mail;
class SendRegisteredMail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
Mail::to($this->user->email)->send(new UserRegistered($this->user));
}
}
そして、ユーザ登録部分にキューを発行する処理を追加します。
ジョブクラスのdispatch()
を実行します。
<?php
namespace App\Http\Controllers\Auth;
use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use App\Jobs\SendRegisteredMail;
class RegisterController extends Controller
{
〜〜〜〜〜
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \App\User
*/
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
]);
SendRegisteredMail::dispatch($user);
return $user;
}
}
さて、これでユーザ登録するとメール送信のキューが発行されます。
しかしこのままだとキューを取り出して処理がされません。
キューワーカでのキューの監視が必要となってきます。
そこでArtisanコマンドでキューワーカを起動します。
$ php artisan queue:work
これでキューが監視され処理されます。ユーザ登録するとメールが送信されたことが確認出来ると思います。
キューワーカのコンソールでも以下のように出力されます。
失敗すると設定した回数分リトライされます。
$ php artisan queue:work
[2019-01-30 02:00:00][2] Processing: App\Jobs\SendRegisteredMail
[2019-01-30 02:00:00][2] Processed: App\Jobs\SendRegisteredMail
公式ドキュメントでも述べられているとおり、キューワーカを永続的に実行するためにはSupervisorのようなプロセスモニタが必要です。
という感じで、キューという仕組みとしてはわかりやすいけれど実装するとしたら難しい機構をLaravelでは手軽に使用出来ることがお分かりいただけたと思います。
公式ドキュメントによるともっと詳細に設定出来るので調べてみるとよいと思います。それでは!
追記
そもそもLaravelのメール送信機能もキューを使ってるっぽいので冗長になっているのでは……