はじめに
Laravelにはジョブとキューと言う機能があります
本記事ではジョブとキューとは何か
そして、ジョブとキューを使って非同期な機能を実装する
サンプルを作成していきます
キュートとは
キューはある決まった処理を非同期で実行する
ための仕組み
キューにジョブを登録していきその処理を実行していく
ジョブとは
ジョブとは処理を実行する本体
になります
キューにジョブが登録され、キューにあるジョブが実行されます
処理自体を担当するのがジョブになります
サンプル作成
では実際に、ジョブとキューを使ったサンプルを作っていき
ジョブとキューの仕組みについて理解していきます
今回作るサンプルは、Userを一覧表示し/{id?}
に対してidの部分にUserのIDを指定します
その指定されたUserの名前に[JOB]と言う文字を付けたり、外したりを非同期で行います
Laravelプロジェクトは各自で作成してください
キュー用のテーブルを作成する
まずジョブが登録されるキューのテーブルを作成していきます
コマンドにて下記を実行してください
$ php artisan queue:table
$ php artisan migrate
これでキュー用のテーブルjobs
キューの実行失敗時に使用されるテーブルfailed_jobs
が作成されます
また、今回使用するUsersテーブルも作成されてるかと思います
また、バージョンの違いによりfailed_jobs
テーブルが作成されていない場合は
下記コマンドを実行し作成してくだ際
$ php artisan queue:failed-table
$ php artisan migrate
これで必要なテーブルは用意できました
サンプルデータの作成
Seederファイルを作成しダミーのデータを作成します
下記コマンド実行
$ php artisan make:seeder PersonTableSeeder
database/seeds
にファイルが作成されます
作成したファイルに追加していきます
<?php
use Illuminate\Database\Seeder;
class PersonTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$param = [
'name' => '太郎',
'email' => 'taro@gmail.com',
'password' => '99999999'
];
DB::table('users')->insert($param);
$param = [
'name' => '花子',
'email' => 'hanako@gmail.com',
'password' => '99999999'
];
DB::table('users')->insert($param);
$param = [
'name' => '次郎',
'email' => 'ziro@gmail.com',
'password' => '99999999'
];
DB::table('users')->insert($param);
}
}
次に作成したシーダファイルを登録します
database/seeds/DatabaseSeeder.php
にて下記を記述してください
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* @return void
*/
public function run()
{
$this->call(PersonTableSeeder::class);
}
}
これでシーダファイルと登録が完了しました
下記コマンドを実行します
$ php artisan db:seed
これでUsersテーブルに3件のダミーデータを用意できました
このデータを一覧表示します
データの表示
まずはコントローラを作成します
$ php artisan make:controller MainController
次にルートの定義をします
Route::get('/{id?}, 'MainController@index');
コントローラーのアクションを実装します
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use App\Jobs\SampleJob;
class MainController extends Controller
{
public function index($id = null) {
if ($id !== null) {
$user = User::find($id);
} else {
$user = null;
}
if ($user != null) {
SampleJob::dispatch($user)->delay(now()->addMinutes(1));
}
$data = User::all();
return view('main.index', compact('data'));
}
}
SampleJob::dispatch($user)
とあります
この部分でジョブを呼び出しています
ジョブはdispatch()
を使い呼び出します
また今回はパスに/{id?}
としているのでidが入っているかどうかを確認し
もしidがあればそのidに該当するユーザーを所得してジョブの発行の際に引数としてジョブにUserを渡してあげてます
delay(now()->addMinutes(1))
これで1分後にジョブを実行する処理をしています
ここまでの処理により、idがあるかを判断しidがあれば該当するUserを所得
Userが存在していればジョブを発行し1分後に実行すると言う処理の実装をしました
次にresources
にmain
ファルだを作成してindex.blade.php
を作成します
index.blade.php
に下記を追加してください
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>ユーザー表示</title>
</head>
<body>
<ul>
@foreach($data as $item)
<li>{{ $item->name }}</li>
@endforeach
</ul>
</body>
</html>
これで、登録したダミーデータをリストで一覧表示することができました
それではこのデータに対して、ジョブとキューを利用して加工していきます
Jobクラスの作成
コマンドにて下記を実行する
$ php artisan make:job SampleJob
実行すると、app/Jjobs
フォルダが作成され中にSampleJob.php
ファイルが作成されています
これがジョブファイルになります
ではジョブファイルに追加していきます
<?php
namespace App\Jobs;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\User;
class SampleJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $user;
public function __construct(User $user)
{
$this->user = $user;
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
$sufix = '[Job]';
if (strpos($this->user->name, $sufix)) {
$this->user->name = str_replace($sufix, '', $this->user->name);
} else {
$this->user->name .= $sufix;
}
$this->user->save();
}
}
ジョブでは実行したい処理をhandle()
メソッドに記入します
そこに記述された処理が実行されています
また、今回の例では__construct()
でUserを受け取っています
このUserはMainController
のindex()
アクションでジョブの発行の際に引数で渡してあげたUserになります
受け取ったUserをプロパティで管理しています
そのUserを使用し、もしUserのnameに[JOB]が含まれていればそれを削除し
含まれていなければ、名前に追加してDBに登録する処理を書いています
これがジョブ自体の処理になります
このジョブの処理を実行したければ先ほどのMainController
のindex()
メソッドで行ったように
dispatch
を使用してジョブを発行させてあげれば良いのです
ただ、これだけではジョブは使用できません
ジョブはサービスプロバイダーに登録してあげる必要があります
サービスプロバイダーの作成
ジョブ登録専用のプロバイダーを作成します
$ php artisan make:provider JobServiceProvider
app/providers
フォルダに作成したプロバイダーファイルが作られます
JobServiceProvider.php
を下記のように記述してください
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class JobServiceProvider extends ServiceProvider
{
/**
* Register services.
*
* @return void
*/
public function register()
{
$this->app->bindMethod(SampleJob::class.'@handle', function($job, $app) {
return $job->handle();
});
}
/**
* Bootstrap services.
*
* @return void
*/
public function boot()
{
//
}
}
register()
メソッドでジョブクラスの登録を行っています
第一引数にジョブクラス名.'@handle'
を渡してあげます
第二引数にクロージャを渡します
クロージャの第一引数にはジョブクラスのインスタンスが渡され、第二引数にはサービスコンテナが渡されます
クロージャ内で$job
ジョブのインスタンスでhandle()
を呼び出すことでジョブが実行できるようにすることができます
ジョブのサービスプロバイダーへの登録は以上になります
最後に.envの編集をします
.evnの編集
デフォルトではキューは同期で動くようになっているため
非同期で動かすために.envでキューをデータベースを利用するように変更します
QUEUE_CONNECTION=database
QUEUE_DIRVER=database
これで全ての準備が完了しました
それでは実際に動作を確認してみましょう
サンプルの実行
ブラウザから/1
とURLを叩いてみましょう
そのまま待ちます
1分後/
にアクセスしてみてください
太郎[JOB]
となっていれば成功です
1分後にジョブを実行するようになっているのでURLで指定したidのユーザーに[JOB]が1分後に付きます
また、ついているユーザーのidを再度叩くことで次は[JOB]が消えることも確認してみてください
また、/1
とアクセスした際にすぐにデータベースのjobsテーブルを確認してみてください
何かデータが入っているかと思います
また、1分後に[JOB]が付いた後に再度jobsテーブルを確認してみてください
中身がなくなっているかと思います
このように発行されたジョブをキューに登録していくことでDBに用意されそれが実行されDBから消えます
これがジョブとキューになり非同期で実行することができました
長くなりましたので最後に簡単にまとめます
まとめ
ジョブとキュートは
- キュートは非同期で処理を実行するもの
- ジョブとは実装する処理そのものである
ジョブとキューを非同期で利用する手順
- ジョブを作成する
- ジョブを登録するサービスプロバイダを作成しジョブを登録する
- キュー専用のテーブルをartisanコマンドで作成する
- .envを編集する
- ジョブのhandle()メソッドに処理を書く
- ジョブを発行したい際にdispatch()を利用してジョブを使用する