LoginSignup
71
51

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分後に実行すると言う処理の実装をしました

次にresourcesmainファルだを作成して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はMainControllerindex()アクションでジョブの発行の際に引数で渡してあげたUserになります
受け取ったUserをプロパティで管理しています
そのUserを使用し、もしUserのnameに[JOB]が含まれていればそれを削除し
含まれていなければ、名前に追加してDBに登録する処理を書いています
これがジョブ自体の処理になります
このジョブの処理を実行したければ先ほどのMainControllerindex()メソッドで行ったように
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でキューをデータベースを利用するように変更します

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()を利用してジョブを使用する
71
51
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
71
51