初めてのLaravelキュー設定と実装方法

Laravel

みなさん、こんにちは!

今回はLaravelのキュー機能について、ご紹介していきたいと思います。

キューを活用することで、メール送信や大量データの処理、外部API連携などの時間のかかる重たい処理をバックグラウンドで実行することができます。これによって、アプリケーションのパフォーマンスが向上し、より良いユーザー体験を提供することができるようになります。

本記事では、Laravelでキューを活用した処理を実装する方法をサンプルコードを交えて具体的に解説していきます。

読者
読者

「Laravelのキューを使ってみたいけど、具体的な実装方法がわからない」

「キューってそもそも何?」

「キューを使うと何ができるの?」

このような疑問をお持ちの方は参考になるかと思います。

それでは、早速みていきましょう!

キューとは何か?

キューというのは、具体的なタスク(ジョブ)を一時的に入れておくことができる箱のようなものだと思ってください。キューは先入れ先だし(FIFO)が特徴で、先に入れたタスクが一番最初に実行されます。

キューを使うと何が嬉しいかというと、冒頭でも説明しましたが、重たい処理をバックグランドで実行することができます。

例えば、外部API連携など重たい処理を実行する際に数十秒待たないと処理が完了しないなどあると、ユーザーとしてはストレスが溜まってしまいますよね。そこで、キューを活用することによって、ユーザーは重たい処理を実行している間も画面を操作したりすることができるようになります。

これによって、ユーザー体験がかなり改善されるということですね。

また、このバックグラウンドで実行しておくことを技術的には「非同期で実行する」と言いますので、覚えておくと良いでしょう。

Laravelでキューを活用する

ここからは、Laravelを使って実際にキューを活用した処理を実装してみましょう。

今回はサンプルなので重たい処理ではなく、普通の登録処理で使いますが、実際には用途を十分に考えて有用なところで使ってください。

サンプルアプリケーションの作成

まずは、題材となるサンプルアプリケーションを作成していきます。今回サンプルとして、アイテム保存アプリケーションを作成してみましょう。

$ composer create-project laravel/laravel=9.x --prefer-dist item_app

雛形をダウンロードできたら、DBの接続設定などを適時行なってください。筆者はMAMP環境で開発を行います。

次に、itemsテーブルを作成します。

$ php artisan make:migration create_items_table

以下のようにマイグレーションファイルを編集します。

public function up()
{
    Schema::create('items', function (Blueprint $table) {
        $table->id();
        $table->string('name')->comment('アイテム名');
        $table->text('description')->comment('アイテムの説明');
        $table->timestamps();
    });
}

次に、ジョブ専用のテーブルを以下のコマンドから作成します。

$ php artisan queue:table

ここまでできたら、マイグレーションしておきます。

$ php artisan migrate

php artisan queue:tableを実行することによって、Laravelは以下のようなジョブ専用のテーブルを作成します。

アイテム一覧画面

まずは、簡単なアイテム一覧画面を作成してみます。

<!-- resources/views/items.blade.php -->

<!DOCTYPE html>
<html lang="ja">
<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>
    <h1>アイテム保存アプリ</h1>
    <form action="{{ route('item.store') }}" method="POST">
        @csrf
        <input type="text" placeholder="アイテム名" name="name" />
        <input type="text" placeholder="説明" name="description" />
        <button type="submit">保存する</button>
    </form>
    <div class="items">
        @foreach ($items as $item)
            <div class="item">
                <h2>{{ $item->name }}</h2>
                <p>{{ $item->description }}</p>
                <hr>
            </div>
        @endforeach
    </div>
</body>
</html>

次に、ルーティングを設定していきます。

Route::get('/items', [ItemController::class, 'index'])->name('items');
Route::post('/item/store', [ItemController::class, 'store'])->name('item.store');

アイテムコントローラとアイテムモデルも作成しておきましょう。

$ php artisan make:controller ItemController
$ php artisan make:model Item

アイテムコントローラを編集します。

// Http/Controllers/ItemController.php

class ItemController extends Controller
{
    public function index()
    {
        $items = Item::all();
        return view('items', ['items' => $items]);
    }
}

アイテムモデルには、更新カラムのホワイトリストを作成しておきましょう。

// Models/Item.php

protected $fillable = ['name', 'description'];

アイテム保存処理

ここが本題の処理です。

キューを使わずに普通に処理するなら、アイテムコントローラには以下のように追記します。

class ItemController extends Controller
{
    ...

    public function store(Request $request)
    {
        $item = new Item();
        $item->fill($this->request)->save();
        return redirect()->route('items');
    }
}

ですが、今回はキューを使っていくため、ここには登録処理は書きません。

キューを使う場合は、キューの設定とジョブのキューへのディスパッチが必要になります。順番の説明していきます。

キューの設定

キューの設定ファイルは「config/queue.php」です。

以下の行でデフォルトのキューに何を使うのかを指定しています。

'default' => env('QUEUE_CONNECTION', 'database'),

キューの種類は、データベースやRedis、Amazon SQSなど色々とありますが、今回は簡単のためにデータベースで進めていきます。.envにキューの接続設定を記述します。

# .env

QUEUE_CONNECTION=database

これでキューの設定はひとまずOKです。

この設定により、キューをデータベースで指定しているので、ジョブをキューに入れた際にデータベースのjobsテーブルにジョブが挿入されることになります。

ジョブの作成

キューの中で実行したい処理はジョブの中に記述していきます。

$ php artisan make:job ItemStoreJob

上記のコマンドを実行すると、「app/Jobs/ItemStoreJob.php」が作成されます。この中にジョブの処理を記述していきます。

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldBeUnique;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\Item;
use Illuminate\Http\Request;

class ItemStoreJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    public $request;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct(array $request)
    {
        $this->request = $request;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $item = new Item();
        $item->fill($this->request)->save();
    }
}

ジョブの本体の処理はhandle()メソッド内に記述していきます。

なお、ジョブの引数としてリクエストデータを配列として受け取れるようにコントストラクターに記述しておきましょう。

キューへのディスパッチ

最後に、アイテム登録時に登録用のジョブをキューへディスパッチしていきます。

ディスパッチというのは、ジョブをキューへ追加することだと思ってください。キューはジョブが入ってきた順番に処理していきます。

今回キューをデータベースとしているので、実際にはデータベースにジョブが順番に入ってきて、処理されることになります。

コントローラの中でItemStoreJobをキューにディスパッチします。

public function store(Request $request)
{
    ItemStoreJob::dispatch($request->all()); // ディスパッチ
    return redirect()->route('items');
}

これで一通り処理は完成です。

ジョブの実行

最後に、ジョブを起動してから動作確認を行なってください。

ジョブを起動するには、以下のコマンドを実行します。

$ php artisan queue:work

キューに入ったジョブの実行が成功した場合は、以下のように「DONE」が表示されます。

失敗した場合は、以下のように「FAIL」が表示されます。

ちなみに、ジョブが失敗した場合は、failed_jobsテーブルに失敗ジョブとエラーメッセージなどのデータが入るようになっています。

まとめ

ここまで、Laravelでキュー活用する方法をサンプルコードを交えて説明してきました。

基本的な流れとしては、ジョブクラスを作成しておき、作成したジョブを処理を行いたいタイミングでキューへディスパッチするだけです。

今回のアイテム保存アプリケーションでは、重たい処理を扱いませんでしたが、数十秒から数分かかるような重たい処理を実行する場合は、その分ユーザーに待たせることになります。このような場合は、キューを活用することでユーザーを待たせずに、次のアクションをサクサク動かせるので、ユーザー体験は劇的に良くなるでしょう。

皆さんも適材適所でぜひキューを活用してみてください。それでは!

コメント

タイトルとURLをコピーしました