【Laravel】JobとQueueを使った非同期処理の作成方法と使い方
この記事からわかること
- LaravelのJob(ジョブ)やQueue(キュー)とは?
- 使い方や設定方法、メリット
index
[open]
\ アプリをリリースしました /
友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-
posted withアプリーチ
Laravelのデフォルトで備わっている機能の「ジョブ」と「キュー」。この機能を使うことで非同期で処理を実行させることができるようになります。今回はこれらの使い方やメリット、設定方法などをまとめていきたいと思います。
基礎知識
はじめに「ジョブ」と「キュー」がどのようなものか整理しておきます。
Job(ジョブ)とは?
Laravelでいう「Job(ジョブ)」とは処理そのもののこと。非同期で処理させたい内容を自分で定義し、そのひとまとまりになった処理自体をジョブと呼ぶ。
Queue(キュー)とは?
「Queue(キュー)」とはジョブを非同期で実行するための仕組みのこと。イメージとしてはキューと呼ばれる箱の中にジョブをためていき、基本的には先入先出法(FIFO)で処理を実行していきます。
キュー(=ジョブの格納場所)はデータベースなどに用意します。「MySQL」といったリレーショナルデータベースや、NoSQLデータベースである「Redis」、AWSの「Amazon SQS」といったキューイングサービスなどと連携させることも可能です。
非同期処理のメリット
「ジョブ」と「キュー」を使うことで非同期処理を行うことができるようになります。非同期処理を行えることで時間のかかる処理を切り離すことができ、処理効率をグッと上げることができます。
例えば会員登録時にアップロードされた画像を編集する処理をジョブとして切り離すことで、データベース登録処理をスムーズに行うことが可能になります。
キューには次々とジョブが溜まっていき、任意のタイミングで実行され、消化されていきます。
まとめ
- ジョブとは処理のこと
- キューとはジョブを非同期で処理させる仕組みのこと
- これらの機能を用いることで非同期処理が可能
- 時間のかかる処理を切り離して実行できる
使い方と前準備
実際にジョブとキューを使って非同期処理を作成するためにはいくつかの前準備が必要です。今回はリレーショナルデータベース(MySQL)にジョブを登録する方法で実践してみます。
必要な前準備と手順
- .envファイルの修正
- DBにキューテーブルの作成
- ジョブクラスの作成
- キューに溜まったジョブを実行する(Worker)
リレーショナルデータベースを使う際は「config/database.php
」にデータベースの設定をすることを忘れないように注意してください。
.envファイルの修正
最初に設定を定義している隠しファイルの「.env」内のQUEUE_CONNECTION変数
の部分を変更します。
QUEUE_CONNECTION=sync
↓
QUEUE_CONNECTION=database
デフォルトではsync(同期)
で実行されるようになっているためこれをデータベースに変更しています。ここを変更していないとジョブはデータベースにたまらず、普通に実行されてしまうので注意してください。
キュードライバも明示的に指定しておくため以下のコードを「.env」に追記しておきます。
QUEUE_DRIVER=database
DBにキューテーブルを作成する
キューテーブルを作成するためのマイグレーションファイルはartisan
コマンドで自動作成できます。作成したらマイグレーションを実行します。
$ php artisan queue:table
Migration created successfully.
$ php artisan migrate
Migrating: 2022_06_07_104702_create_jobs_table
Migrated: 2022_06_07_104702_create_jobs_table (60.91ms)
これでdatabase/migrations
ディレクトリ内に20XX_XX_XX_XXXXXXX_create_jobs_table.php
が作成され、紐づけているデータベースにも「jobsテーブル」が生成されています。
マイグレーションファイル(一部)
public function up()
{
Schema::create('jobs', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('queue')->index();
$table->longText('payload');
$table->unsignedTinyInteger('attempts');
$table->unsignedInteger('reserved_at')->nullable();
$table->unsignedInteger('available_at');
$table->unsignedInteger('created_at');
});
}
ジョブクラスの作成
ジョブクラスはapp/jobs
内に格納します。専用のmake
コマンドが用意されているので実行すると自動でjobs
ディレクトリと該当ファイルが生成されます。
$ php artisan make:job TestJobs
Job created successfully.
app/jobs/TestJobs
<?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\User;
class TestJobs implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
/**
* Create a new job instance.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// ここに処理を記述する
// 例:エロクアントを用いたDBへのインサート処理
$user = new User;
$user->name = "jobs";
$tech->save();
}
}
ジョブクラスの中にはhandleメソッド
が用意されます。キューからジョブが呼び出された時に実行させたい処理をここに記述します。
上記は例としてエロクアントを用いたDBへのインサート処理を記述しています。
あとはジョブを溜めたい箇所でdispatch
メソッドを呼び出すだけです。その際はuse
文で読み込むのを忘れないようにしてください。今回はアクセスされた時にジョブを溜めるような仕組みを作ってみます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
// 追記
use App\jobs\TestJobs;
class appController extends Controller
{
public function index(Request $request)
{
// ジョブを溜める
TestJobs::dispatch();
return view('index');
}
}
ルーティングでこのコントローラーのindex
アクションメソッドを実行するように設定すれば、アクセスされたタイミングでデータベースにジョブが溜まります。溜まったジョブはこのままでは実行されないのでコマンドを叩いて実行させます。
キューに溜まったジョブを実行する(Worker)
キューに溜まったジョブはWorkerを使って実行させます。Workerは以下のコマンドで起動し、ジョブを実行してくれます。
$ php artisan queue:work
[2022-06-07 11:24:58][1] Processing: App\Jobs\TestJobs
[2022-06-07 11:24:58][1] Processed: App\Jobs\TestJobs
正常に終了するとデータベース内に溜まっていたジョブは自動で消去されます。
Workerの起動時のオプション
Workerの起動時にオプションを渡すことも可能です。
キューから1個のジョブのみ実行
$ php artisan queue:work --once
キューから100個のジョブを実行
$ php artisan queue:work --max-jobs=100
キューにある全てのジョブを実行
$ php artisan queue:work --stop-when-empty
キューにあるジョブを1時間の間だけ実行
$ php artisan queue:work --max-time=3600
キューにあるジョブの優先度が高いものから実行
$ php artisan queue:work --queue=high,low
キューの名前を指定して実行
$ php artisan queue:work --queue=キューの名前
キューの名前はdispatch
メソッドのonQueue
メソッドで指定できます。
TestJobs::dispatch()->onQueue('foo');
条件付きでディスパッチさせる
TestJobs::dispatchIf($judge);
ジョブを溜めずに同期処理としてディスパッチ
TestJobs::dispatchSync();
ジョブに引数を渡す
TestJobs::dispatch($foo);
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。