この記事はニフティグループ Advent Calendar 2018の11日目の記事です。
以降では、Laravel(5.7)で非同期処理を実装してHorizonで動かしてみる、ということをしてみます。
(Laravelが動く環境はすでにあることを想定しています。Laradocなどで作成しておいてください。)
目次
- Laravel(5.7)で非同期処理を実装する
- 非同期に実行したい処理を実装する
- コントローラーから呼び出す
- 試しに同期的に実行してみる
- Redisキューを使って動かしてみる
- Laravel Horizonで動かしてみる
- さいごに
1. Laravel(5.7)で非同期処理を実装する
LaravelにはQueueサービスというものがあり、Beanstalkd、Amazon SQS、Redisなどをキューとして用いた非同期処理が簡単に実装できます。
詳しくは公式のドキュメントを御覧ください。
1.1 非同期に実行したい処理を実装する
以下のコマンドを実行すると、app/Jobs
配下にProcessSample
というクラスが生成されます。このクラスに非同期処理(ジョブ)を実装していきます。
php artisan make:job ProcessSample
作成したクラスの 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;
class ProcessSample implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
private $text;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct($text)
{
$this->text = $text;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
logger()->info("It's work! | ".$this->text);
}
}
1.2 コントローラーから呼び出す
dispatch
という関数でジョブをキューに追加します。
引数は ProcessSample
のコンストラクタに渡されます。
use App\Jobs\ProcessSample;
Route::get('/test/{text}', function ($text) {
ProcessSample::dispatch($text);
return 'Queued!';
});
1.3 試しに同期的に実行してみる
.env
ファイルのQUEUE_CONNECTION
が実際にどのキューを使うかの設定です。
Amazon SQSやRedisなどを指定することができます。
ここではまず動くか確かめたいので、同期的に実行するようsync
と設定します。
QUEUE_CONNECTION=sync
さきほど/test/{text}
というURLを設定したので/test/sampletext
にアクセスしてみます。
[2018-12-11 **:**:**] local.INFO: It's work! | sampletext
このようなログが出力されていたら成功です🎉
2. Redisキューを使って動かしてみる
Redisを準備する
Redis本体は各自ご用意ください。
LaradocであればRedisは含まれているので以下で起動できます。
docker-compose up -d redis
パッケージの追加と設定
LaravelでRedisをキューとして使うにはPredisが必要なので、プロジェクトに追加します。
composer require predis/predis
Redisをキューとして使うように設定します。
QUEUE_CONNECTION=redis
# 以下は環境に合わせて設定してください
REDIS_HOST=redis
REDIS_PASSWORD=null
REDIS_PORT=6379
Redisの設定は以上です!
動かしてみる
次は実際にキューを監視させます。
php artisan queue:work
この状態で/test/sampletext2
にアクセスしてみます。
[2018-12-11 **:**:**] local.INFO: It's work! | sampletext2
このようなログが出力されていたら成功です🎉
非同期処理の実装、完璧です✨
3. Laravel Horizonで動かしてみる
HorizonはLaravelのRedisキューの監視ツールです。
非同期処理をする分には上記までの手順で問題ないのですが、Horizonにはダッシュボードがあり、処理のスループットや失敗などを確認することができて楽しいので使ってみます。
詳しくは公式のドキュメントを御覧ください。
パッケージの追加
Horizonをプロジェクトに追加します。
composer require laravel/horizon
Horizonはpcntlが必須です。ないと以下のようなエラーが表示されます。
$ composer require laravel/horizon
Using version ^2.0 for laravel/horizon
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.
Problem 1
- laravel/horizon v2.0.0 requires ext-pcntl * -> the requested PHP extension pcntl is missing from your system.
- laravel/horizon 2.0.x-dev requires ext-pcntl * -> the requested PHP extension pcntl is missing from your system.
- Installation request for laravel/horizon ^2.0 -> satisfiable by laravel/horizon[2.0.x-dev, v2.0.0].
Installation failed, reverting ./composer.json to its original content.
Dockerを使っている方はDockerファイルに以下を追加してからビルド&再起動で動く可能性があります。
どうにかしてpcntlをインストールしてください。
(略)
RUN docker-php-ext-install pcntl
docker-compose up -d --build
セットアップ
Horizonをインストールします。
php artisan horizon:install
失敗したキューのためのテーブルを作成します。
php artisan queue:failed-table
php artisan migrate
Horizonの準備は以上です!
動かしてみる
Horizonを起動します。
php artisan horizon
/horizon
にアクセスすると、ダッシュボードが表示されるはずです。
この状態で/test/sampletext3
にアクセスしてみます。
[2018-12-11 **:**:**] local.INFO: It's work! | sampletext3
ログが出力されていたら成功です。
おつかれさまでした👏
あとはもっとカスタマイズしたり、exit(1)
で異常終了させたりして遊べます。
失敗したジョブ一覧から失敗したジョブをもう一度動かしてみることも可能です。
4. さいごに
非同期処理はLaravelがきちんとお世話してくれるので、簡単に実装できることがわかりました。
あとはSupervisorなどを用いてよしなにやればきちんと動くはずです。
動かしてみるだけでしたが、Horizonについてもご紹介しました。
Horizonにはその他認証、待ち状態が長いときの通知など機能がもりもりなので、ぜひ公式のドキュメントをチェックしてみてください。