Gateway

Gateway ロック

理由

  • 1 つの Gateway プロセスのみが状態ディレクトリを所有する必要があります。追加の Gateway は、分離されたプロファイル、状態ディレクトリ、設定、およびポートを使用して実行します。
  • 古いロックファイルを残すことなく、クラッシュや SIGKILL に耐えます。
  • 別の Gateway がすでにポートを所有している場合、明確なエラーですぐに失敗します。

3 つのレイヤー

起動時には、次の 3 つの手順を順番に実行して所有権を強制します。

  1. 状態所有権ロックは、正規化された状態ディレクトリをキーとするロックを取得します。OPENCLAW_ALLOW_MULTI_GATEWAY=1で起動された Gateway を含むすべての Gateway が対象となるため、破壊的な SQLite メンテナンスが稼働中の所有者と競合することはありません。
  2. 設定ロックは、従来の設定ごとのロックを取得し、ランタイムポートを記録します。マルチ Gateway モードでは、この設定シングルトンをスキップしますが、状態所有権ロックは維持します。
  3. ソケットバインドは、HTTP/WebSocket リスナー(デフォルトは ws://127.0.0.1:18789)を排他的な TCP リスナーとしてバインドします。

各レイヤーは個別に失敗する可能性があり、それぞれ固有の GatewayLockError をスローします。

状態ロックと設定ロック

  • ロックの生存確認には、記録された PID、利用可能な場合はプラットフォームのプロセス開始 ID、および Gateway プロセス ID が使用されます。検証済みの所有者は、そのポートがリッスンを開始する前の起動中も正式な所有者として扱われます。

  • 専用の SQLite コーディネーターが、メタデータの検査、古い所有者の回収、およびロックの置き換えを直列化します。その排他トランザクションは、所有プロセスがクラッシュした場合に自動的に解放されます。

  • ロックファイルが存在しない場合、または記録された所有プロセスが終了している場合、起動処理はロックを回収して続行します。

  • いずれかのロックが使用中の場合、起動処理は最大 5 秒間(デフォルト)再試行してから断念します。

    text
    GatewayLockError("gateway はすでに実行中です(pid <pid>)。<ms>ms 後にロックがタイムアウトしました")

ソケットバインド

  • EADDRINUSEの場合、最近終了したプロセス後の TIME_WAIT 期間を乗り切るため、起動処理は 500ms 間隔で最大 20 回(合計約 10 秒間)バインドを再試行します。

  • 再試行後もポートが使用中の場合:

    text
    GatewayLockError("別の gateway インスタンスがすでに ws://127.0.0.1:<port> でリッスンしています")
  • その他のバインドエラー:

    text
    GatewayLockError("ws://127.0.0.1:<port> で gateway ソケットをバインドできませんでした: <cause>")

シャットダウン時に、Gateway は HTTP/WebSocket サーバーを閉じ、状態ロックファイルと 設定ロックファイルを削除します。

運用上の注意

  • 別の Gateway ではないプロセスがポートを占有している場合も、エラーは同じです。ポートを解放するか、openclaw gateway --port <port>で別のポートを選択してください。
  • OPENCLAW_ALLOW_MULTI_GATEWAY=1では、複数の設定/ランタイムインスタンスを使用できますが、変更可能な状態を共有することはできません。各インスタンスには引き続き一意の OPENCLAW_STATE_DIR が必要です。
  • サービススーパーバイザーの管理下では、上記のいずれかのエラーが発生した新しい Gateway プロセスは、まず既存プロセスの /healthz をプローブします。そのプロセスが正常な場合、新しいプロセスは失敗せず、既存プロセスに制御を委ねます。systemd では、終了コード 78 で終了します。ユニットの RestartPreventExitStatus=78 により、Restart=always がロックまたは EADDRINUSE の競合でループするのを防ぎます。既存プロセスが正常にならない場合、ヘルスプローブの再試行は時間制限付きで行われ、その後、起動処理は無限にループせず、上記のロックエラーで失敗します。
  • macOS アプリは Gateway を生成する前に独自の軽量 PID ガードを使用しますが、実際のランタイム強制を担うのは上記のファイルロックとソケットバインドです。

関連項目

Was this useful?
On this page

On this page