RitoLabo

laravel5.5のキュー投入によるジョブ処理を導入する

  • 公開:
  • 更新:
  • カテゴリ: PHP Laravel
  • タグ: Laravel,artisan,5.5,Events,Queues,dispatch,Job,Redis,Amazon SQS,Beanstalk

LaravelのようなPHPフレームワークでアプリケーションを構築すると、各々の役割に応じた処理別にソースコードを分離でき、可読性の高い開発が行えます。

しかしながら、その規模が大きくなってくるとさまざまな処理が増えてきます。その度にコントローラの仕事が増え、疎結合感が無くなってくるストレスもある中で、ある一つの処理が大きな処理時間を必要とした場合にはもうたまったものではありません。

しかもそれがユーザの待機時間にも影響を与えるとなるともうこれは…ただただ泣けます。

そんな時は処理をキューへ投入し、遅延処理を行いましょう。laravelのジョブキュー処理を実装すると非同期での処理を実現でき、ユーザへのレスポンスを劇的に早める事ができます。

メール送信やログ処理など、ユーザへのページ表示に関係なく、かつ重たい処理でユーザを待たせたくないですしね。

という事で今回は、laravel5.5のキューサービスを利用し、ジョブ処理を実装します。

今回のデモ環境は以下の通りです。

  • Linux CentOS7
  • Apache 2.4
  • MySQL 5.7
  • PHP 7.1
  • Laravel 5.5

尚、上記環境でなくても、artisanコマンドを叩ける環境であれば同手順で実装可能です。

また、laravelフレームワークのルートディレクトリを「laravel/」とします。

アジェンダ
  1. キューサービスについて
  2. キューサービスの設定
  3. ジョブクラスの作成
    1. ジョブクラス生成
    2. ジョブクラス実装
  4. コントローラ・ビュー・ルーティングの作成
  5. ジョブのディスパッチ
  6. 動作確認

キューサービスについて

Laravelが対応しているキューサービスについては、以下になります。

sync
外部環境やサービスを必要とせずにキュー&ジョブを実装できます。キューサービスのロジックをまず実装する場合におすすめですが、事実上、同期処理となり遅延処理にはなりません。
database
データベースを使ってキュー&ジョブ管理を行います。
Beanstalk
Beanstalkdという、オープンソースのジョブキュークライアントツールです。 これを利用するには、Beanstalkdの構築が必要です。
http://kr.github.io/beanstalkd/
Amazon SQS
AWSが提供しているキューサービスです。無料利用期間であれば無料枠がありますが、基本的には有料です。
https://aws.amazon.com/jp/sqs/
Redis
NoSQLデータベースです。オープンソースですが、利用にはRedisの構築が必要です。
https://redis.io

という事で、今回はジョブキューの導入が主な目的なので、はじめの一歩としてsyncを使ってサクッと実装してみましょう。

キューサービスの設定

どのキューサービスを使うかの設定は、laravel/config/queue.phpで行います。開いて見てみます。

<?php

return [

/*
|--------------------------------------------------------------------------
| Default Queue Driver
|--------------------------------------------------------------------------
|
| Laravel's queue API supports an assortment of back-ends via a single
| API, giving you convenient access to each back-end using the same
| syntax for each one. Here you may set the default queue driver.
|
| Supported: "sync", "database", "beanstalkd", "sqs", "redis", "null"
|
*/

'default' => env('QUEUE_DRIVER', 'sync'),

/*
|--------------------------------------------------------------------------
| Queue Connections
|--------------------------------------------------------------------------
|
| Here you may configure the connection information for each server that
| is used by your application. A default configuration has been added
| for each back-end shipped with Laravel. You are free to add more.
|
*/

'connections' => [

'sync' => [
'driver' => 'sync',
],

'database' => [
'driver' => 'database',
'table' => 'jobs',
'queue' => 'default',
'retry_after' => 90,
],

'beanstalkd' => [
'driver' => 'beanstalkd',
'host' => 'localhost',
'queue' => 'default',
'retry_after' => 90,
],

'sqs' => [
'driver' => 'sqs',
'key' => 'your-public-key',
'secret' => 'your-secret-key',
'prefix' => 'https://sqs.us-east-1.amazonaws.com/your-account-id',
'queue' => 'your-queue-name',
'region' => 'us-east-1',
],

'redis' => [
'driver' => 'redis',
'connection' => 'default',
'queue' => 'default',
'retry_after' => 90,
],

],

/*
|--------------------------------------------------------------------------
| Failed Queue Jobs
|--------------------------------------------------------------------------
|
| These options configure the behavior of failed queue job logging so you
| can control which database and table are used to store the jobs that
| have failed. You may change them to any database / table you wish.
|
*/

'failed' => [
'database' => env('DB_CONNECTION', 'mysql'),
'table' => 'failed_jobs',
],

];
default
利用するキューサービスを設定します。 記述が.envファイルからの読み込みとなっている為、laravel/.envを確認してみます。
QUEUE_DRIVER=sync
Laravel5.5では、デフォルトでsyncが設定されているため、今回は変更なしでOKです。
connections
各キューサービスの設定を行っています。
failed
失敗したジョブのロギングの動作を設定しています。 ここで書き込むデータベースとテーブルを指定できます。

ジョブクラスの作成

それではここから手を動かしていきます。

と、その前に、言い遅れましたが今回は「テキストファイルを作成し保存する処理」を実装して、それをジョブ化して処理していく流れにしますので、今回のジョブクラスは「StoreText」とします。

ジョブクラス生成

ではまずはジョブクラスの作成です。laravelルートディレクトリへ移動し、以下のartisanコマンドを叩いてジョブクラスを生成します。

# laravelルートディレクトリへ移動
cd /path/to/laravel

# artisanコマンドでジョブクラス生成する
php artisan make:job StoreText

# 実行結果
[demo@localhost laravel]# php artisan make:job StoreText
Job created successfully.

laravel/app/Jobsディレクトリが作成され、その中にジョブクラスStoreText.phpが生成されます。

laravel
├─ app
│ ├─ Jobs
   └─ StoreText.php

ジョブクラス実装

それでは生成したジョブクラスに処理を記述していきます。 まずはソースコードを見てみます。

laravel/app/Jobs/StoreText.php
<?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 StoreText 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()
{
//
}
}

コンストラクタとhandle()メソッドというシンプルなものになっています。

コンストラクタにデータセットを記述し、メイン処理はhandle()メソッドに記述していきます。 以下のようになります。

<?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 StoreText implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

protected $param;

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

/**
* Execute the job.
*
* @return void
*/
public function handle()
{
// テキストファイル作成
$file = sprintf('%s/%s.txt', storage_path('texts'), date('Q-Ymd-His'));
touch($file);
// 書き込み
$current = file_get_contents($file);
$current .= $this->param;
file_put_contents($file, $current);
}
}

メンバ変数「$param」を定義し、コンストラクタでは、キュー投入時に渡される引数「$value」をメンバ変数「$param」へ格納しています。そして、handle()メソッドにテキストファイルを作成する処理を記述しています。

ジョブクラスはこれで実装完了です。

コントローラ・ビュー・ルーティングの作成

それではこのジョブクラスを動作させるために、コントローラとビューを簡単に実装してルーティングを行います。

ここは簡単に組むので、ダイジェストでソースだけ記します。

ルーティング
laravel/routes/web.php
Route::get('sample/queues', 'SampleController@queues');
http://YOURDOMAIN/sample/queuesへのアクセス時にSampleControllerのqueuesメソッドを実行します。
コントローラ
laravel/app/Http/Controllers/SampleController.php
public function queues()
{
return view('sample_queues');
}
単純に、sample_queuesビューを返します。
ビュー
laravel/resources/views/sample_queues.php
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>Sample Queues</title>
</head>
<body>
<p>
Queues test!!
</p>
</body>
</html>
ここには特別な処理は無く、「Queues test!!」と表示されるだけです。

最後に、生成したテキストファイルを格納するためのディレクトリ「texts」をlaravel/storage配下へ作成します。

laravel
├─ storage
│ └── texts

ジョブのディスパッチ

それでは仕上げです。作成したジョブをコントローラに組み込み、キューへ投入します。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Jobs\StoreText; // ジョブクラスをuseする

class SampleController extends Controller
{
public function queues()
{
$text = str_random(1000);

// ジョブをディスパッチする
$this->dispatch(new StoreText($text));

return view('sample_queues');
}
}

ジョブクラスをuseし、ジョブをディスパッチします。また、引数にはランダムに生成した100文字を渡しています。

動作確認

全ての実装が完了したので、ブラウザからアクセスしジョブが実行されているか確認してみます。

処理の流れとしては以下となります。

  1. http://YOURDOMAIN/sample/queuesにアクセス
  2. コントローラ内でテキスト作成の処理をキューへ投入し、ビューを表示させる
  3. キューへ投入されたジョブが実行され、laravel/storage/textsにテキストファイルが生成される。

ブラウザから動作確認

laravel
├─ storage
│ └── texts
│  └── Q-20171118-171936.txt

ジョブが実行され、テキストファイルが生成されている事が確認できました。

まとめ

以上でキュー&ジョブの導入は完了となります。

今回はsyncキューを利用した為、実質的な遅延処理は行われていませんが、ここまで実装が出来たのなら、あとは別のキューサービスに切り替えればよいだけです。

という事で、次回はデータベースを使ってジョブキューを実装し、本格的に遅延処理を行いたいと思います。

next:laravel5.5のデータベースキュー投入とジョブ処理で非同期処理を実現する