プラグイン開発
NocoBase クラスターEnterprise Edition+背景にある課題
シングルノード環境では、プラグインは通常、プロセス内の状態、イベント、またはタスクを通じて要件を満たすことができます。しかし、クラスターモードでは、同じプラグインが複数のインスタンスで同時に実行される可能性があり、以下のような典型的な課題に直面します。
- 状態の一貫性:設定や実行時のデータがメモリにのみ保存されている場合、インスタンス間で同期するのが難しく、ダーティリードや重複実行が発生しやすくなります。
- タスクスケジューリング:明確なキューイングと確認メカニズムがない場合、時間のかかるタスクが複数のインスタンスによって同時に実行されてしまう可能性があります。
- 競合状態:スキーマ変更やリソース割り当てに関わる操作では、並行書き込みによる競合を避けるために、操作をシーケンシャルに処理する必要があります。
NocoBase のコアは、アプリケーション層に様々なミドルウェアインターフェースをプリセットしています。これにより、プラグインがクラスター環境で共通の機能を再 利用できるようになります。以下では、キャッシュ、同期メッセージ、メッセージキュー、分散ロックの利用方法とベストプラクティスを、ソースコードと合わせてご紹介します。
解決策
キャッシュコンポーネント(Cache)
メモリに保存する必要があるデータには、システムに組み込まれているキャッシュコンポーネントを使用することをお勧めします。
app.cacheを介してデフォルトのキャッシュインスタンスを取得します。Cacheはset/get/del/resetといった基本的な操作を提供します。また、キャッシュロジックをカプセル化するためのwrapやwrapWithCondition、そしてmset/mget/mdelのようなバッチメソッドもサポートしています。- クラスターデプロイ時には、共有データを永続化機能を持つストレージ(Redisなど)に配置し、インスタンスの再起動によるキャッシュの損失を防ぐために、適切な
ttlを設定することをお勧めします。
例:plugin-auth におけるキャッシュの初期化と使用
プラグインでのキャッシュの作成と使用
同期メッセージマネージャー(SyncMessageManager)
メモリ内の状態が分散キャッシュで管理できない場合(例えば、シリアライズできない場合)、ユーザー操作によって状態が変化した際には、その変化を同期シグナルを通じて他のインスタンスに通知し、状態の一貫性を保つ必要があります。
- プラグインの基底クラスには
sendSyncMessageが実装されており、内部でapp.syncMessageManager.publishを呼び出し、チャネルにアプリケーションレベルのプレフィックスを自動で追加することで、チャネルの衝突を防ぎます。 publishではtransactionを指定でき、メッセージはデータベーストランザクションがコミットされた後に送信されるため、状態とメッセージの同期が保証されます。handleSyncMessageを通じて他のインスタンスから送信されたメッセージを処理します。beforeLoadフェーズで購読することができ、設定変更やスキーマ同期などのシナリオに非常に適しています。
例:plugin-data-source-main が同期メッセージを使用して複数ノード間のスキーマ一貫性を維持する
プラグイン内でのスキーマ更新の同期
メッセージブロードキャストマネージャー(PubSubManager)
メッセージブロードキャストは同期シグナルの基盤となるコンポーネントであり、直接使用することも可能です。インスタンス間でメッセージをブロードキャストする必要がある場合に、このコンポーネントを利用できます。
app.pubSubManager.subscribe(channel, handler, { debounce })を使用してインスタンス間でチャネルを購読できます。debounceオプションは、重複ブロードキャストによる頻繁なコールバックを防ぐためのデバウンス処理に使用されます。publishはskipSelf(デフォルトは true)とonlySelfをサポートしており、メッセージが現在のインスタンスに送り返されるかどうかを制御します。- アプリケーション起動前にアダプター(Redis、RabbitMQなど)を 設定する必要があります。設定しない場合、デフォルトでは外部メッセージシステムには接続されません。
例:plugin-async-task-manager が PubSub を使用してタスクキャンセルイベントをブロードキャストする
タスクキャンセルシグナルのブロードキャスト

