コンテンツにスキップ

アーキテクチャ

このページは作成中です。内容は不完全または変更される可能性があります。

WippyはGo上に構築されたレイヤードシステムです。コンポーネントは依存関係順に初期化され、イベントバスを通じて通信し、ワークスティーリングスケジューラを介してLuaプロセスを実行します。

レイヤーコンポーネント
アプリケーションLuaプロセス、関数、ワークフロー
ランタイムLuaエンジン(gopher-lua)、50以上のモジュール
サービスHTTP、キュー、ストレージ、Temporal
システムトポロジー、ファクトリー、関数、コントラクト
コアスケジューラ、レジストリ、ディスパッチャ、イベントバス、リレー
インフラストラクチャAppContext、ロガー、トランスコーダ

各レイヤーは下位のレイヤーにのみ依存します。コアレイヤーは基本的なプリミティブを提供し、サービスはその上に高レベルの抽象化を構築します。

アプリケーションの起動は4つのフェーズを経て進行します。

フェーズ1: インフラストラクチャ

Section titled “フェーズ1: インフラストラクチャ”

コンポーネントがロードされる前にコアインフラストラクチャを作成:

コンポーネント目的
AppContextコンポーネント参照用のシールドディクショナリ
EventBusコンポーネント間通信のためのPub/Sub
Transcoderペイロードシリアライゼーション(JSON、YAML、Lua)
Loggerイベントストリーミング付き構造化ログ
Relayメッセージルーティング(Node、Router、Mailbox)

フェーズ2: コンポーネントロード

Section titled “フェーズ2: コンポーネントロード”

Loaderはトポロジカルソートで依存関係を解決し、レベルごとにコンポーネントをロードします。同じレベルのコンポーネントは並列にロードされます。

コアコンポーネント(PIDGen、Dispatcher、Registry、Finder、Supervisor)が最初に初期化され、続いてシステムコンポーネント(Topology、Lifecycle、Factory、Functions、Contracts)が初期化されます。具体的なレベルは依存グラフから実行時に計算されるため、コンポーネントの追加・削除に応じて順序が適応します。

各コンポーネントはLoadフェーズ中にコンテキストに自身をアタッチし、依存コンポーネントがサービスを利用可能にします。

フェーズ3: アクティベーション

Section titled “フェーズ3: アクティベーション”

すべてのコンポーネントがロードされた後:

  1. Dispatcherをフリーズ - ロックフリールックアップのためにコマンドハンドラレジストリをロック
  2. AppContextをシール - 書き込み不可、ロックフリー読み取りを有効化
  3. コンポーネントを開始 - Starterインターフェースを持つ各コンポーネントのStart()を呼び出し

レジストリエントリ(YAMLファイルから)がロードされ検証:

  1. プロジェクトファイルからエントリをパース
  2. パイプラインステージがエントリを変換(オーバーライド、リンク、バイトコード)
  3. auto_start: trueとマークされたサービスが実行開始
  4. スーパーバイザーが登録されたサービスをモニタリング

コンポーネントはアプリケーションライフサイクルに参加するGoサービスです。

フェーズメソッド目的
LoadLoad(ctx) (ctx, error)初期化してコンテキストにアタッチ
StartStart(ctx) errorアクティブな操作を開始
StopStop(ctx) errorグレースフルシャットダウン

コンポーネントは依存関係を宣言します。Loaderは有向非巡回グラフを構築し、トポロジカル順序で実行します。シャットダウンは逆順で発生します。

コンポーネント依存関係目的
PIDGenなしプロセスID生成
DispatcherPIDGenコマンドハンドラディスパッチ
RegistryDispatcherエントリストレージとバージョニング
FinderRegistryエントリルックアップと検索
SupervisorRegistryサービス再起動ポリシー
TopologySupervisorプロセスの親子ツリー
LifecycleTopologyサービスライフサイクル管理
FactoryLifecycleプロセス生成
FunctionsFactoryステートレス関数呼び出し

コンポーネント間通信のための非同期Pub/Sub。

  • 単一のディスパッチャgoroutineがすべてのイベントを処理
  • キューベースのアクション配信でパブリッシャーのブロックを防止
  • パターンマッチングは正確なトピックとワイルドカード(*)をサポート
  • コンテキストベースのライフサイクルでサブスクリプションをキャンセルに結びつけ
sequenceDiagram
participant P as パブリッシャー
participant B as イベントバス
participant S as サブスクライバー
P->>B: Publish(topic, data)
B->>B: パターンマッチング
B->>S: アクションをキュー
S->>S: コールバック実行

トピックは <system>:<kind> の形式です。組み込みシステムが発行するもの:

SystemKind目的
registryentry.create, entry.update, entry.delete, entry.accept, entry.rejectエントリの変更
registryregistry.begin, registry.commit, registry.discardトランザクション境界
processfactory.register, factory.delete, factory.accept, factory.rejectプロセス種別のファクトリ登録
supervisorservice.register, service.remove, service.update, service.start, service.stopサービスライフサイクル

エントリ定義のバージョン付きストレージ。

  • バージョン付き状態 - 各変更で新バージョンを作成
  • 履歴 - 監査証跡用のSQLiteバック履歴
  • 監視 - 特定のエントリの変更を監視
  • イベント駆動 - 変更時にイベントをパブリッシュ
flowchart LR
YAML[YAMLファイル] --> Parser
Parser --> Stages[パイプラインステージ]
Stages --> Registry
Registry --> Validation
Validation --> Active

パイプラインステージがエントリを変換:

ステージ目的
Override設定オーバーライドを適用
Disableパターンでエントリを削除
Link要件と依存関係を解決
BytecodeLuaをバイトコードにコンパイル
EmbedFSファイルシステムエントリを収集

ノード間のプロセス間メッセージルーティング。

flowchart LR
subgraph Router
Local[ローカルノード] --> Peer[ピアノード]
Peer --> Inter[インターノード]
end
Local -.- L[同一プロセス]
Peer -.- P[同一クラスター]
Inter -.- I[リモート]
  1. ローカル - 同一ノード内での直接配信
  2. ピア - クラスター内のピアノードに転送
  3. インターノード - ネットワーク経由でリモートノードにルーティング

各ノードはワーカープール付きのメールボックスを持つ:

  • FNV-1aハッシングで送信者をワーカーに割り当て
  • 送信者ごとのメッセージ順序を保持
  • ワーカーがメッセージを並行処理
  • キューがいっぱいになるとバックプレッシャー

コンポーネント参照用のシールドディクショナリ。

プロパティ動作
シール前ブート中のシングルスレッド書き込み
シール後ロックフリー読み取り、書き込み時panicパニック
重複キーパニック
型安全性型付きゲッター関数

コンポーネントはLoadフェーズ中にサービスをアタッチします。ブート完了後、AppContextは最適な読み取りパフォーマンスのためにシールされます。

グレースフルシャットダウンは依存関係の逆順で進行:

  1. SIGINT/SIGTERMがシャットダウンをトリガー
  2. Supervisorが管理対象サービスを停止
  3. Stopperインターフェースを持つコンポーネントがStop()を受信
  4. インフラストラクチャのクリーンアップ

2回目のシグナルで即座に終了。