カテゴリー: BackEnd

Laravelで非同期実行する

はじめに

バックエンドの実装に関して、時間がかかる処理を行う場合、非同期に処理したいケースがあると思います。今回はLaravelで非同期に処理するための手軽な方法を紹介します。

動作環境

本記事ではPHP 7.2、Laravel 5.5の環境を想定しています。

準備

非同期に処理するに当たりジョブのキューを管理する方法としては、データベースを利用する方法やRedisを利用する方法などがあります。Laravelでは標準でデータベース、Redis、Amazon SQS、Beanstalkdを利用することができますが、今回は最も手頃なデータベースを使用する実装を紹介します。

デーブルの作成

以下のコマンドを実行してキューを管理するためのテーブルを作成します。

$ php artisan queue:table
$ php artisan migrate

このコマンドを実行すると、以下ようなテーブルが作成されます。

mysql> show columns from jobs;
+--------------+---------------------+------+-----+---------+----------------+
| Field        | Type                | Null | Key | Default | Extra          |
+--------------+---------------------+------+-----+---------+----------------+
| id           | bigint(20) unsigned | NO   | PRI | NULL    | auto_increment |
| queue        | varchar(255)        | NO   | MUL | NULL    |                |
| payload      | longtext            | NO   |     | NULL    |                |
| attempts     | tinyint(3) unsigned | NO   |     | NULL    |                |
| reserved_at  | int(10) unsigned    | YES  |     | NULL    |                |
| available_at | int(10) unsigned    | NO   |     | NULL    |                |
| created_at   | int(10) unsigned    | NO   |     | NULL    |                |
+--------------+---------------------+------+-----+---------+----------------+

.envの修正

ドライバはデフォルトでは sync になっていますので、 database に変更します。

QUEUE_DRIVER=database

ジョブの作成

それでは、非同期で処理するジョブを実装していきます。ユーザー登録時に何らかの処理を行う想定です。なお、ユーザーテーブルは既に定義してあるものとします。

以下のコマンドでジョブクラスを作成します。作成したクラスは app/Jobs ディレクトリに配置されます。

php artisan make:job AfterUserRegister

このコマンドで作成されるジョブクラスを見てみましょう。

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

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

    public function __construct()
    {
        //
    }

    public function handle()
    {
        //
    }
}

見て分かる通り、ジョブクラスは実行時に呼び出されるhundleメソッドのみあります。なお、ジョブクラスにはEloquentモデルを渡すことができます。ディスパッチ時に渡される引数は以下のようにコンストラクタで取得できます。

<?php

namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

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

    protected $user;

    public function __construct(User $user)
    {
        // dispatchメソッドの引数でわたされる
        $this->user = $user;
    }

    public function handle()
    {
        // ジョブで処理する内容
    }
}

ジョブのディスパッチ

ジョブのディスパッチには実装したジョブクラスの dispatch メソッドで行います。以下はコントローラでディスパッチする例です。

<?php

namespace App\Http\Controllers;

use App\User;
use App\Jobs\AfterUserRegister;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class UsersController extends Controller
{
    public function store(Request $request)
    {
        // ユーザ作成
        $user = User::create($request->all());

        AfterUserRegister::dispatch($user);
    }
}

キューワーカーを起動

キューを処理するためにはキューワーカーを起動する必要があります。以下のコマンドでキューワーカーを起動します。

$ php artisan queue:work

なお、キューワーカーは長時間起動しっぱなしのプロセスなので、コードを変更した場合はリスタートする必要があります。キューワーカーのリスタートは以下のコマンドで行います。

$ php artisan queue:restart

より細かな制御

ここまでで非同期にジョブを処理することができるようになりました。ここからは、より細かな制御について紹介します。

特定のキューにディスパッチする

ディスパッチするキューを指定することで、優先的に処理することがなどが可能です。キューの指定には onQueue メソッドを使います。

<?php

namespace App\Http\Controllers;

use App\User;
use App\Jobs\AfterUserRegister;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;

class UsersController extends Controller
{
    public function store(Request $request)
    {
        // ユーザ作成
        $user = User::create($request->all());

        AfterUserRegister::dispatch($user)->onQueue('high');
    }
}

最大試行回数の指定

ジョブの最大試行回数は以下のように指定します。

<?php

namespace App\Jobs;

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

    // 最大試行回数
    public $tries = 5;
}

タイムアウトの指定

ジョブの最大実効秒数は以下のように指定します。

<?php

namespace App\Jobs;

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

    // タイムアウト(秒)
    public $timeout = 90;
}

ジョブ失敗時の処理

最大試行回数以上ジョブの実行に失敗した場合、そのジョブは failed_jobs テーブルに保存されます。以下のコマンドでテーブルを作成します。

$ php artisan queue:failed-table
$ php artisan migrate

失敗したジョブのクリーンアップ

失敗したジョブのクリーンアップはジョブクラスの failed メソッドで行います。なお、引数として失敗の原因となった Exception が渡されます。

<?php

namespace App\Jobs;

use App\User;
use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

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

    // 最大試行回数
    public $tries = 5;

    protected $user;

    public function __construct(User $user)
    {
        // dispatchメソッドの引数でわたされる
        $this->user = $user;
    }

    public function handle()
    {
        // ジョブで処理する内容
    }

    public function failed(Exception $exception)
    {
        // 失敗時のクリーンアップ
    }
}

失敗したジョブの再実行

failed_jobs テーブルに保存されたジョブは以下のコマンドで確認できます。

$ php artisan queue:failed

失敗したジョブの再実行は以下のコマンドで行います。

// ID=5のジョブを再実行する場合
$ php artisan queue:retry 5

// 失敗したジョブを全て再実行する場合
$ php artisan queue:retry all

また、失敗したジョブの削除は以下のコマンドで行います。

// ID=5の失敗ジョブを削除する場合
$ php artisan queue:forget 5

// 全ての失敗ジョブを削除する場合
$ php artisan queue:flush

さいごに

Laravelで非同期に処理を行う方法として、データベースを使う方法を紹介しました。

おすすめ書籍

     

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: phplaravel

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

4週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前