はじめに
このフレームワークでは常駐型処理状態のステータス管理を可能にするため、イベントハンドラをキューとステータスUNIT(単にUNITとも言います)という単位に分けて最適化を行います。
また、各UNITに特定のステータスを割り当てる事によって状態遷移を制御させる事ができるので、複雑で柔軟なシーケンスに対応できるようになっていて、ここではその概念的なものを押さえておきます。
キューとUNITの事をざっくり説明すると、以下のような関係になります。
■UNIT(ステータスUNIT)
イベント処理の最小単位
■キュー
1つのイベントを処理するためのUNITの集合(言わば静的に配置されたタスクの待ち行列のようなもの)
このアーキテクチャは、後に出てくるランタイムUNIT定義クラスを実装する際の共通インターフェースとして機能し、モジュール単位の入れ替えが容易にできる設計になっています。
排他制御・実行順序の保障
このキューとステータスUNITの仕組みにより、一般的なイベント駆動型プログラミングとは異なる以下の特長を実現しています。
排他実行の保障
各イベントハンドラが処理中であっても、同じハンドラが重複して呼ばれることはありません。
これは、キューに登録されている全ステータスUNITの処理完了を監視しながら、コアクラスであるCycleDrivenManagerが実行を一元管理しているため、同一のハンドラ処理が重複して並行実行されることなく、排他的に順次処理されます。
UNIT処理順序の保障
デベロッパーにより意図的に「スローブレイク」(フレームワーク内でステータスを維持したままハンドラ処理を中断する機能)を実行したとしても、登録されたステータスUNITの処理順序はCycleDrivenManagerによって厳密に保証され、意図した通りのイベント順序と整合性を保つことが可能です。
以降では、サービスランチャーの実装を仮定して、イベントが発生してからキューとUNITを使ってどのように処理されるのか、その内容を見ていきます。
イベント処理の基本構成
サービスランチャーと言えば、登録されているサービスに対して死活監視を行い、停止しているサービスがあれば自動再起動を行うような動作は一般に良く知られていますが、以降ではその動作モデルを単純な基本構成として見ていきます。
■エントリポイント(アプリ起動時に必ず呼ばれる処理)
【処理①】サービスの死活監視を行う
【処理②】停止しているサービスを起動する
上記の処理構成を常駐的に繰り返しているものとして、これをキューとUNITで構成すると以下のようになります。
■キュー名:STARTUP
①ステータス名:process_watch
【処理】サービスの死活監視を行う
②ステータス名:process_start
【処理】停止しているサービスを起動する
上記の例ではアプリ起動時のキュー名を割り当て、個々の処理単位にUNITとしてのステータス名をそれぞれ割り当てています。
SocketManagerクラスを使う場合とは異なり、予約されているキューはSTARTUPキューのみなので、より簡易的になります。
以降では、これを基本構成としてUNITの代表的な使用例を見ていきます。
再配置UNITとして使う
クロスプラットフォーム環境では、サービスの死活監視を行ったり、サービスを起動したりするためのAPIはOSによって異なります。そこで、それぞれのプラットフォームで同じ動作を実現するために処理を分ける必要が出てきます。
例えばWindows環境とLinux環境とで処理を分ける場合、STARTUPキューに適用するUNITを以下のように構成する事ができます。
■キュー名:STARTUP(Windows構成)
①ステータス名:process_watch
【処理】サービスの死活監視を行う
②ステータス名:process_start
【処理】停止しているサービスを起動する
■キュー名:STARTUP(Linux構成)
①´ステータス名:process_watch
【処理】サービスの死活監視を行う
②´ステータス名:process_start
【処理】停止しているサービスを起動する
上記の場合、キューはどちらも同じものですが、①と②がWindows用の実装で、①´と②´がLinux用の実装といった具合に処理が分かれています。
UNIT定義クラスでは、キューに割り当てるUNITを動的に配置するメソッドが用意されているため、UNIT登録時にそれぞれのプラットフォームに応じた処理の振り分けが可能になります。
ポーリングUNITとして使う
■キュー名:STARTUP
①ステータス名:process_watch
【処理】サービスの死活監視を行う
・検査対象のサービスが停止している場合 process_start ステータスを返して②のUNITへ状態遷移する
・検査対象のサービスが動作している場合 process_watch ステータスを返して①のUNITへ留まる
【戻り値】process_watch or process_start
②ステータス名:process_start
【処理】停止しているサービスを起動する
【戻り値】process_watch
UNITの状態遷移先は戻り値で返すステータスによって決まります。
②のUNITに関しては、サービスの死活監視の際に動作中である事が確認できれば処理する必要はありません。
そこで①のUNITで検査対象のサービスが動作中である事が確認できれば process_watch ステータスを返して①のUNITに留まり、停止中である事を確認した場合は process_start ステータスを返す事で②のUNITへ状態遷移させる事ができます。
UNIT集合の種類
SocketManagerクラスでは、UNIT定義をプロトコル部とコマンド(ビジネスロジック)部に分ける必要がありましたが、RuntimeManagerではランタイムUNIT(いわゆるビジネスロジック部)のみになるのでより簡易的になります。
これを踏まえると、以下の関係が成り立ちます。
■UNIT(ステータスUNIT)
イベント処理の最小単位
■キュー
一つのイベントを処理するためのUNITの集合(言わば静的に配置されたタスクの待ち行列のようなもの)
■ランタイムUNIT
ビジネスロジック部分にあたるキューの集合
このランタイムUNIT部分はクラス定義なので、そのクラスを入れ替える事で別のビジネスロジックに入れ替える事が可能になっています。
以下のメイン処理クラスを生成する場合と同じように、このクラスもコマンドでひな形を生成できるので、デベロッパーはクラス内のキューとUNITの開発に集中して取り組む事ができます。
おわりに
RuntimeManagerで予約されているキューは STARTUP のみですが、自身でオリジナルキューを作る事もできます。
キューのボリュームが増えてきたり、再利用UNITなどを使ってソースを最適化するニーズが出てくる状況に応じて使い分けるといいでしょう。