74
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Laravelでジョブとキューを理解する

Posted at

#はじめに
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()を利用してジョブを使用する
74
52
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
74
52

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?