#はじめに
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`にファイルが作成されます
作成したファイルに追加していきます
```PersonTableSeeder.php
<?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
```
次にルートの定義をします
```web.php
Route::get('/{id?}, 'MainController@index');
```
コントローラーのアクションを実装します
```MainController.php
<?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`に下記を追加してください
```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`ファイルが作成されています
これがジョブファイルになります
ではジョブファイルに追加していきます
```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`を下記のように記述してください
```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でキューをデータベースを利用するように変更します
```.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()を利用してジョブを使用する