tanaka's Programming Memo

プログラミングについてのメモ。

Laravel(5.3) のキューを試す

Laravel公式ドキュメント:Queues - Laravel - The PHP Framework For Web Artisans
和訳ページ:キュー 5.2 Laravel

公式ドキュメントを参考に、Laravelのキューを動かしてみました。ドライバーは、まずは sync で動かして、その後に database を使いました。

はじめに

この項目は、公式ドキュメントからの意訳です。

Laravelのキュー(queue)は、 BeanstalkやAmazon SQS, Redis, RDBなどの様々なキューを統一したAPIで扱えるようにするものです。メールを送信するなどの時間がかかる処理を、その場で完了するのではなく、後回しにすることができます。これにより、アプリケーションのWebリクエストがすぐにレスポンスを返せるようになります。

Queueの設定は config/queue.php で定義します。このファイルを見れば、Laravelが利用できるキューの設定を見ることができます。ローカルユーザーは、 synchronous ドライバーが使えます。 キュードライバーが null の場合は、キューされたジョブは破棄されます。

前提

  • macOS Sierra
  • PHP5.6以降
  • MySQL 5.7.11
  • node、Laravel、Composerはインストール済み

プロジェクトを準備

以下の手順で、テスト用のプロジェクトを作成します。

  • ターミナルを起動して、プロジェクトを作成したいフォルダーに移動する
  • 環境を更新
composer global update
npm update -g npm
npm update -g
  • 以下を実行して、Laravelプロジェクトを作成し、プロジェクトフォルダーに移動して、サーバーを起動する
laravel new laravel-queue-test
cd laravel-queue-test
php artisan serve

以上で準備完了です。Webブラウザを起動して、 http://localhost:8000 にアクセスすると、インストールしたLaravelプロジェクトが表示されます。

デフォルトでは、キューはローカルで同期的に動作する sync ドライバーが設定されています。本来のキューのメリットは得られませんが、ローカル環境ですぐに動作を確認することはできるので、まずは動かしてみましょう。

ジョブの作成

デフォルトでは、キューに積むことができるジョブは、 app/Jobs ディレクトリー内に置きます。最初はこのディレクトリーは存在せず、 artisan の make:job コマンドでジョブを作成する時に自動的に作成されます。

試しにログを出力するジョブとして、 LogExample を作成するには、ターミナルで以下のようにします。

php artisan make:job LogExample

app/Jobs/LogExample.php が作成されるので、エディターで開いてみましょう。作成されたジョブのクラスは、あらかじめ Illuminate\Contracts\Queue\ShouldQueue インターフェースが実装(implements)されます。このインターフェースを実装すると、Laravelは処理を同期的に実行せず、キューにジョブを積むようになります。

クラスの構造

Jobクラスはとてもシンプルです。通常は コンストラクター(__construct)と handle メソッドだけを持ちます。 handle メソッドは、キューによってジョブが実行される時に呼ばれます。

ログにメッセージを書き出すジョブを試しに作ります。

  • app/Jobs/LogExample.php を開く
  • Logを利用するために以下の use 文を最初の方に追加
use Illuminate\Support\Facades\Log;
  • 処理を handle メソッドに追加
    public function handle()
    {
        Log::info('ジョブテスト');
    }

ジョブを実行する

ジョブクラスを作成したら、 dispatch ヘルパーを使って呼び出します。dispatch ヘルパーには、ジョブのインスタンスを渡します。

  • routes/web.php を開く
  • ジョブを使うための use をファイルの上の方に追加する
use App\Jobs\LogExample;
  • getのルートに dispatch ヘルパーを追加して、以下のようにする
Route::get('/', function () {
    dispatch(new LogExample);

    return 'ログへの出力ジョブを実行しました。';
});

http://localhost:8000/ をWebブラウザーで開くと、「ログへの出力ジョブを実行しました。」というメッセージが画面に表示されて、ジョブが実行されます。 storage/logs/laravel.log を開いて確認してください。「ジョブテスト」というログが書き込まれています。

遅延実行

ジョブの実行を遅らせて実行することができます。ジョブのインスタンスの delay メソッドを呼びます。このメソッドは、 Illuminate\Bus\Queueable トレイトによって提供されます。 artisan でジョブを作成していれば、自動的に宣言されます。

ジョブの実行を5秒遅らせてみます。

  • routes/web.php を開く
  • getメソッド内のジョブの呼び出し部分を以下のように修正する
Route::get('/', function () {
    $job = (new LogExample)->delay(5);
    dispatch($job);

    return 'ログへの出力ジョブを実行しました。';
});

5秒経過してからログが書き込まれることを想定していましたが、すぐに書き込まれてしまいました。これは sync ドライバーはローカル上でキューの動作を確認するためのもので、非同期処理に対応していないからです。

データベースのキュードライバーに変更して、改めて動作を確認しましょう。

キュードライバーをデータベースに切り替える

以下、MySQLの例です。

  • ターミナルから、以下を実行して、MySQLを起動して、ログインする
sudo mysql.server start
mysql -u ユーザー名 -p
  • パスワードを入力してログインする
  • テスト実行用のデータベースを作成する
create database laravel-queue-test;
exit
  • .env をテキストエディターなどで開く
  • DB_から始まるデータベースの設定を、環境に合わせて設定
  • QUEUE_DRIVERの設定をデータベースに変更
QUEUE_DRIVER=database
  • .env を上書き保存する
  • ターミナルで以下を実行して、キュー用のテーブルを作成する
php artisan queue:table
php artisan migrate
  • 設定を変更したので、反映させるためにLaravelのサービスを再起動する
    • Laravelのサービスを動かしているターミナルで [control]+[C] でサービスを停止
    • php artisan serve でLaravelサービスを起動
  • キューを実行するために、以下をターミナルで実行
php artisan queue:work

改めて、 storage/logs/laravel.log を開いてから、 http://localhost:8000/ を読み込んでください。今度は、5秒ほど経過してから、ログが書き込まれます。

Amazon SQSでは、遅延実行は 15分までの制限があります。


以上で、Laravelでキューを使うことができるようになりました。他のドライバーの使い方や、より発展的な使い方は、公式サイトなどを参照してください。

      • -

ConnectionとQueue

config/queue.php を見ると、様々なバックエンドサービスに接続するための connections の設定があります。それらの設定によって、ドライバーや接続情報、キューの種類などを設定できます。異なるスタックや優先順位が違うキューを複数、用意することができます。

queue.php の connections 配列を見ると 'queue' 属性が設定されているものがあります。キューに積む時に、何も指定しない場合は 'default' のキューに送られます。明示的に指定したい場合は、 dispatchメソッドをチェーンさせて、 onQueue メソッドを使います。

// デフォルトのキューに送られます
dispatch(new Job);

// "emails"キューに送られます
dispatch(new Job)->onQueue('emails');

複数のキューにジョブを送らないアプリケーションでは、一つのシンプルなキューの方が良いですが、複数のキューにジョブを送ることができれば、ジョブに優先順位をつけたり、ジョブの処理をセグメント化することができるので使いやすくなります。Laravelのキューワーカーは、優先度によって処理を特定することができます。例えば、ジョブを high キューに送信するならば、そのワーカーに高い処理の優先度を与えると良いでしょう。

php artisan queue:work --queue=high, default

ドライバーの前提条件

Database

キュードライバーに database を選択した場合、ジョブをデータベースのテーブルに記録するので、そのためのテーブルが必要です。データベースへの接続設定を行い、Laravelアプリケーションのためのデータベースを作成した上で、以下でテーブルを作成します。

php artisan queue:table
php artisan migrate

その他のドライバーの前提条件

以下のそれぞれのドライバーに必要なものです。


ひとまず、以上。