【ランタイムUNITクラスの実装】

はじめに

ビジネスロジックの要であるこのランタイムUNITクラスは、キューとステータスUNITを活用して常駐型処理の状態遷移を柔軟に制御する高機能なクラスです。
従来のSocketManagerクラスではプロトコルUNITやコマンドUNITが必要でしたが、ランタイムライブラリではプロトコルを必要とせず、このランタイムUNITクラスがビジネスロジック部分に特化しているため、より軽量かつシンプルな構成になっています。

さらに、スキャフォールディング(コード自動生成)機能に対応しており、イベントループ上で動作するビジネスロジックをテンプレートベースのクラス単位で効率的に管理できます。
これにより、SocketManagerクラスと同様にクラスの差し替えも容易になり、柔軟な拡張やメンテナンスが可能です。

ランタイムUNITクラスを生成するコマンドは以下の通り。
> php worker runtime:units RuntimeForTest

[success] ランタイムUNITクラスの生成に成功しました (RuntimeForTest)
[success] ランタイムUNITのキュー名Enumの生成に成功しました (RuntimeForTestQueueEnum)
[success] ランタイムUNITのステータス名Enumの生成に成功しました (RuntimeForTestStatusEnum)
                    

コマンドを実行する事でapp/RuntimeUnitsの場所に以下3つのファイルが生成されます。
・RuntimeForTest
IEntryUnitsインターフェースがimplementsされたランタイムUNITクラスです。
ここに常駐型処理のイベントハンドラを実装します。
・RuntimeForTestQueueEnum
ここに常駐型処理のキュー(イベント)名を定義します。
・RuntimeForTestStatusEnum
ここに常駐型処理のステータス(UNIT)名を定義します。
このフレームワーク環境では、キュー名とステータス名をEnumで定義する事を推奨しているので、それぞれのEnumファイルに分けて出力されます。

以降では生成されたファイルの内容を見ていきます。

キュー名の定義

RuntimeForTestQueueEnum.php のファイルは、イベントに対応するキュー名を定義するEnumファイルです。
ランタイムUNITのキュー名はあらかじめRuntimeQueueEnumで予約されていますので、生成されたEnumファイルにはその内容が代入されています。
定義済みのキュー名は RuntimeQueueEnum::STARTUP のみで、アプリ起動時に必ず呼ばれます。
また、任意のキュー名も追加可能で、ランタイムUNITクラスで定義されるイベントごとのUNITの集合を特定するために使用されます。

今回のケースでは RuntimeForTest クラス内でキューとUNITの紐づけを行います。
紐づけの方法は以下の>> ランタイムUNITクラスの実装の項で説明しています。

ステータス名の定義

RuntimeForTestStatusEnum.php のファイルは、ランタイムUNITのステータス名を定義するEnumファイルです。
ランタイムUNITのステータス名であらかじめ予約されているものは StatusEnum::START のみで、生成されたEnumファイルにはその内容が代入されています。
それ以外のステータス名は自由に定義する事ができます。
定義済みのステータス名は以下の通り。
RuntimeForTestStatusEnum::START
同じキューに登録されているUNITの集合のうち一番最初に実行されるステータスです。
UNITは必ずSTARTステータスから始まるルールになっています。
これらのステータス名はランタイムUNITクラスで定義したUNITに紐づくものなので、今回のケースでは先ほど生成した RuntimeForTest クラス内でUNITとステータス名の紐づけを行います。
紐づけの方法は以下の>> ランタイムUNITクラスの実装の項で説明しています。

※ここで定義したステータス名は異なるキューで再利用が可能です。

ランタイムUNITクラスの実装

RuntimeForTest.php のファイルにはUNIT定義を含めた各種メソッドが実装されています。
各メソッドの仕様と実装例は以下の通り。

➤キューリストの取得

フレームワークは以下のメソッドをコールして必要なキューのリストを登録します。
【メソッド】getQueueList(): array

【パラメータ】なし

【戻り値】array - キュー名のリスト
                    

例えば▶イベントハンドラについてのページでご紹介したサービスランチャーを例に挙げると、以下のように実装します。
protected const QUEUE_LIST = [
    RuntimeQueueEnumForLauncher::STARTUP->value     // 起動処理のキュー
];
public function getQueueList(): array
{
    return (array)static::QUEUE_LIST;
}
                    


➤ステータスUNITリストの取得

以下のメソッドがフレームワーク内部でコールされる事によって、キューとUNITの紐づけが登録されます。
【メソッド】getUnitList(string $p_que): array

【パラメータ】
    $p_que - string - 必須 - キュー名

【戻り値】array - キューごとのUNIT集合のリスト(連想配列)
                    

フレームワーク内部では getQueueList メソッドで取得したキュー名を元に、getUnitList メソッドがコールされるため、引数にはキュー名が渡されます。
例えば▶イベントハンドラについてのページでご紹介したサービスランチャーを例に挙げると、引数で与えられたキュー名に対応するリストを以下のように登録します。
public function getUnitList(string $p_que): array
{
    $ret = [];

    // STARTUPキューのUNIT集合を登録
    if($p_que === RuntimeForTestQueueEnum::STARTUP->value)
    {
        // PROCESS_WATCHステータスとUNIT(getProcessWatch)の紐づけ
        $ret[] = [
            'status' => RuntimeForTestStatusEnum::PROCESS_WATCH->value,
            'unit' => $this->getProcessWatch()
        ];
        // PROCESS_STARTステータスとUNIT(getProcessStart)の紐づけ
        $ret[] = [
            'status' => RuntimeForTestStatusEnum::PROCESS_START->value,
            'unit' => $this->getProcessStart()
        ];
    }

    .
    .
    .
    return $ret;
}
                    


➤ステータスUNITの実装

ここでは getUnitList メソッド内で紐づけたUNITを定義します。
【メソッド】<任意のメソッド名>(): Closure|string|null

【パラメータ】なし

【戻り値】
    Closure|string
    - ステータスUNITの定義: Closure
        パラメータ:
            $p_param - RuntimeManagerParameter - 必須 - UNITパラメータクラスのインスタンス
                各イベントハンドラで共通の引数として使用されるインスタンス。
                RuntimeManagerParameterクラスを継承した拡張クラスを指定する事も可能。
        戻り値: string|null
            - 遷移先がある場合: string
                遷移先のキュー名
            - 遷移先がない(終了する)場合: null
    - ステータスUNITの定義: string
        ヘルパー関数などの関数名
                    

以下では STARTUP キューのUNIT集合をポーリングUNITを使って実装した例をご紹介しています。
ポーリングUNITの詳細については▶イベントハンドラについての説明をご覧ください。
protected function getProcessWatch()
{
    return function(ParameterForTest $p_param): ?string
    {
        $pid = $p_param->pid;   // プロセスIDをUNITパラメータクラスで管理している場合
        if(file_exist('/proc/{$pid}'))
        {
            // サービスが稼働中であればポーリング
            return RuntimeForTestStatusEnum::PROCESS_WATCH->value;
        }

        // PROCESS_START ステータスのUNIT(getProcessStart)へ遷移
        return RuntimeForTestStatusEnum::PROCESS_START->value;
    };
}
protected function getProcessStart()
{
    return function(ParameterForTest $p_param): ?string
    {
        $cmd = $p_param->cmd;   // コマンド文をUNITパラメータクラスで管理している場合
        $output = null;
        $retval = null;
        exec($cmd, $output, $retval);
        if($retval === 0)
        {
            echo "サービスを起動しました\n";
        }
        else
        {
            echo "サービスを起動できませんでした\n";
        }

        // PROCESS_WATCH ステータスのUNIT(getProcessWatch)へ遷移
        return RuntimeForTestStatusEnum::PROCESS_WATCH->value;
    };
}
                    


※UNITパラメータクラスには▶UNITパラメータクラスのページで使用した ParameterForTest を指定しています。

おわりに

生成されたクラスのインスタンスは、メイン処理クラス内で $manager->setRuntimeUnits() メソッドに引き渡す事で適用されます。
複数のランタイムUNITクラスやメイン処理クラスを用意している場合は、常駐型アプリの実装内容によって最適なインスタンスを動的、あるいは静的に適用する事で柔軟なアプリ構築が可能になります。