はじめに
ビジネスロジックを記述する上で処理の高速化は命題です。
が、それにも限界はあります。ではどうすればいいのか?見た目上でも早くなればいいのに。
画面上の操作はトリガに留めて、メイン処理はバックグラウンドで処理すればいいじゃない!
ということでQueueにぶっ込んで非同期的に処理を実行する方法を調べてみました!
#やりたいこと
データベース上にキューをスタックするテーブルを作り、画面操作をトリガとしてスタックする。
スタックしたデータは一定時間経過後に実行する。
非同期的に処理を行いたい。
最終的には*の部分はajax通信で処理状態を取得できるようにし、Web画面の状況を更新していくようにしたいが・・・。
Queueの実行について
実装に移る前に、以下の設定を行う必要があります。
- config/queue.php
- .env
- database(migration file)
##config/queue.php
return [
'default' => env('QUEUE_DRIVER', 'database' /* ここを書き換える */),
'connections' => [
'sync' => [
'driver' => 'sync',
],
'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'expire' => 60,
],
// and more...
],
'failed' => [
'database' => env('DB_CONNECTION', 'mysql_laravel'),
'table' => 'failed_jobs',
],
];
###それぞれの説明
name | discryption |
---|---|
sync | 設定していない場合の標準。その名の通り同期的に処理を行うため、Queue最大の恩恵である非同期処理は行えない。 |
database | データベースをジョブキューとして代用する。非同期処理が行えるようになるが事前のマイグレーションが必須。 |
beanstalkd | こういうの。詳しくはググってね。 |
sqs, iron | お金かかるっぽいのでパス。ググ(ry |
redis | インメモリDB的なやつ。名前は聞くけど詳しいことは知らない。インメモリDBの欠点である揮発性を克服して高速に処理できるっぽい。かがくの ちからって すげー! |
とりあえずsyncでテストした後にdatabaseで実装するという段取りで試してみた。
##.env
# ...
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_DATABASE=sample_db
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
# ここを sync->database に書き換える
QUEUE_DRIVER=database
# ...
ここのQUEUE_DRIVER
の値をsync
からdatabase
に書き換える。
実はここでめちゃくちゃハマりました。
Laravel名物、envファイルに泣かされるってやつです。
configファイルいじっても改善されない・・・あるある。
##migration
マイグレーションは簡単で、コンソールから次のコマンドを打つだけ。
$ php artisan queue:table
$ php artisan queue:failed-table
$ php artisan migrate
#Queueファイル作成
次にコンソールからジョブを作っていきます。
$ php artisan make:job SampleJob --queued
ここでは超簡単なジョブ、「投入された時間と実行された時間をログに吐く」というサンプルアプリケーションを作ってみて実際に動かしてみます。
namespace App\Jobs;
use App\Jobs\Job;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Bus\SelfHandling;
use Illuminate\Contracts\Queue\ShouldQueue;
class SampleJob extends Job implements SelfHandling, ShouldQueue
{
use InteractsWithQueue, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$queued_at = date('Y-m-d H:i:s');
sleep(5);
$dispatched_at = date('Y-m-d H:i:s');
\Log::info("処理開始 - {$queued_at} ... 処理終了 - {$dispatched_at}");
}
}
なお、トリガは次のようにしてみました。
Route::get('/queue', function() {
Queue::push(new \App\Jobs\SampleJob());
return 'At ' . date('Y-m-d H:i:s') . ' - queue pushed.';
});
##実行
早速ブラウザからhttp\://192.168.10.10/queue
に接続してみると・・・。
こんな画面になるはずです。
ついでにMySQLの中身を見てみると・・・。
こんな感じになってます。
しかし、今の段階ではQueueにスタックされているだけで、ジョブの実行はされていません。いつまで待ってもされません。
とりあえずartisan
から次のコマンドを叩いてJobを実行してみる。
$ php artisan queue:work
これで処理が実行されてます。
試しにstorage/logs
の中身を見てみると、
[2017-09-09 00:58:19] local.INFO: 処理開始 - 2017-09-09 00:58:14 ... 処理終了 - 2017-09-09 00:58:19
というようにちゃんとログが吐き出されていることと思います。
#所感
かなりハマったけど、分かればなんということはないところで引っかかっているというのはもはやいつものこと。
とりあえずキューが使える環境は整ったので、今後はドキュメント読みながら組み上げていきたいですね。
最終的にはコマンドと組み合わせてバッチ処理を作りたいなぁ。
#参考