💼

Laravelに (Octaneと一緒に)RoadRunner Jobsを導入する

2024/08/31に公開

初めに

前回の記事で LaravelにOctane/RoadRunner を導入した際に、ついでにRoadRunner Jobsを導入して使ってみた結果を書きました。
ですが実際の導入の仕方を書いていなかったので書きます。

PHPのバージョン:8.3
Laravelのバージョン:10
Octaneのバージョン:2.4
RoadRunnerのバージョン:2024-2

Octane・RoadRunnerのインストール

公式のやり方に従って、OctaneとRoadRunnerを導入します(説明は割愛)

RoadRunner Jobsのインストール

公式のやり方に従って RoadRunner JobsのPHP側ライブラリを導入してください
(RRサーバーには標準でインストール済み)

Octaneの起動の仕方を変える

Octaneを使ってRoadRunnerを導入したときに1点問題があってそれは、
Octaneを使ってRoadRunnerを導入すると、RoadRunnerの標準的な設定ファイルである .rr.yaml が生成されず、効かない状態になっています。

RoadRunner Jobsを使いたい場合、自分でワーカースクリプトを用意して、JobのリクエストとHTTPリクエストを分岐させて処理する必要があります。なのでいくつか修正をして、

  • rr.yamlを正常に読み込むようにする
  • カスタムワーカースクリプトが動作するようにする
    必要があります。それではやってみましょう。

Octane -> RoadRunnerへの設定の渡し方の問題でしかないので、今後のバージョンアップで変わる可能性が十分にあることをご留意ください。
その場合、
vendor/laravel/octane/src/Commands 以下のPHPファイルを見て修正してください

Octaneの起動コマンドを変える

導入時はOctaneの起動コマンドに色々なオプションがついていると思うのですが、それを必要最低限にします
導入時に起動コマンドがどうなっているのか覚えていないので、私のプロジェクトの現状のコマンドを下に示します。
php -d variables_order=EGPCS /var/www/html/artisan octane:start --server=roadrunner --rpc-host=0.0.0.0 --rpc-port=6001

config/octane.php の修正

以下の記述を追加してください
rr-worker.php はカスタムワーカースクリプト名です。

'host' => env('OCTANE_HOST', '0.0.0.0'),
'port' => env('OCTANE_PORT', '8080'),
'roadrunner' => [
     'command' => env('OCTANE_ROADRUNNER_COMMAND', 'rr-worker.php'),
]

.rr.yaml の記載

公式を参考に記載してみてください
参考に私のプロジェクトの設定を挙げます。
色々いじくり回しているので変なところがあるかもしれません
https://gist.github.com/takeyamakenta/24353e776bd0155e755fef289b3ba8cc

カスタムワーカースクリプト

カスタムワーカースクリプトを作ります。
ワーカースクリプトはRoadRunnerが起動したワーカーのエントリポイントに当たるPHPスクリプトです。基本的な動作としては

  • リクエストの待ち受け
  • リクエストのRouting (リクエストの種類や起動すべきJobを判別)
    を行います。
    こちらも公式を参考に書いてくださいと言いたいところですが、Octane経由で導入した場合すでにOctaneのワーカースクリプトがあり、そちらとの兼ね合いがあります。
    以下に私の例を示します。

rr-worker.php

#!/usr/bin/env php
<?php
namespace Composer;
require __DIR__ . '/vendor/autoload.php';

$GLOBALS['_composer_bin_dir'] = __DIR__;
$GLOBALS['_composer_autoload_path'] = __DIR__ . '/..'.'/autoload.php';

use Spiral\RoadRunner\Environment;
use App\Enums\Console\RoadRunnerModes;
use App\Console\RoadRunner\Dispatchers\JobDispatcher;

// Create environment
$env = Environment::fromGlobals();
$jobDispatcher = new JobDispatcher();
if($env->getMode() === RoadRunnerModes::Http->value) {
    // HTTP リクエストの場合Octane側のスクリプトを起動する
    return include __DIR__ . '/vendor/bin/roadrunner-worker';
} else if ($jobDispatcher->canServe($env)) {
    // Job リクエストの場合、JobDispatcherを使って処理を行う
    return $jobDispatcher->serve(__DIR__);
}

$env = Spiral\RoadRunner\Environment::fromGlobals();
でRRの環境変数を取得してHTTPリクエスト用のワーカーか判定し、HTTPリクエストならばOctaneが用意したワーカーに処理を渡しています。
それ以外の場合自作した JobDispatcher と言うクラスに処理を渡しています。

App\Enums\Console\RoadRunnerModes はリクエストの種類を列挙しているだけです
参考
$jobDispatcher->canServe($env) はリクエストがJobかどうか判定しているだけです

JobDispatcher
長いのでGistにします
https://gist.github.com/takeyamakenta/6f76372cd2a634a2d9263f968b02492d

ポイントとしては
https://gist.github.com/takeyamakenta/6f76372cd2a634a2d9263f968b02492d#file-gistfile1-txt-L48
でRoadRunnerのPHPクライアントを生成した後
https://gist.github.com/takeyamakenta/6f76372cd2a634a2d9263f968b02492d#file-gistfile1-txt-L58
でOctaneの仕組みの中でランタイムを生成しています
(正直これらの役割についてはあやふやなので、ご興味のある方はRoadRunnerやOctaneのコードリーディングを頑張ってみてください!)

ここでJobごとの分岐をおこなっています。
$nameにはJobのクラス名を渡す想定です。これはJobをDispatchするときにパラメータとして設定可能です(後述)。もちろん別のパラメータでも良いです。
https://gist.github.com/takeyamakenta/6f76372cd2a634a2d9263f968b02492d#file-gistfile1-txt-L65

Laravel\Octane\Worker::handleTask($job)
で渡した$jobをクロージャとして実行してくれます。
https://gist.github.com/takeyamakenta/6f76372cd2a634a2d9263f968b02492d#file-gistfile1-txt-L67

Jobのディスパッチ

Jobをディスパッチする場合次のようにしてみてください

$rpc  = Spiral\Goridge\RPC\RPC::create('tcp://127.0.0.1:6001');
$jobs = new Spiral\RoadRunner\Jobs\Jobs($rpc);
$payload = [
    (任意)
];
$queue = $jobs->connect('local');
$task = $queue->create(
    XXXJob::class, // Jobのクラス名
    json_encode($payload, JSON_UNESCAPED_UNICODE)
);
$queue->dispatch($task);

これでうまくいくはずです。
長々とした説明になりましたが参考にしてOctane + RoadRunner Jobsを導入してみてください!

Discussion