カナリア比率や skills.d 切片だけ整えても、同一 Label の launchd が二重登録されたままだとノードごとに別プロセスが立ち、LB の数字は健全でも実体が食い違います。clustervps の複数 Mac では doctor --deep でサービス発見を掃き、重複を bootout してから カナリア用ポート帯Webhook 失敗要約を同じ検証テーブルに載せると、再現ドリルが短くなります。

比率ゲートと切片の本編はカナリア・スキル切片・探針合算(マルチ AZ)、ワークフロー隔離はフラグメントマージとカナリア分流、テナント分割と合成プローブはテナント分割・doctor・Webhook 要約、網関配線はマルチ AZ 網関と Webhook。索引はブログ一覧

本稿の位置づけ(カナリア稿との役割分担)

既稿は「LB 重み・semver ディレクトリ・合算 readiness」に軸足があります。本稿はその前段として、plist のコピペや退避用 LaunchAgent が残した重複 LabelListenURL の衝突環境変数の漂流doctor --deep の JSON に落とし込み、ノード横断で突き合わせる手順です。掃除が終わって初めて、カナリア用のポート切片と失敗要約のドリルが意味を持ちます。

doctor --deep と重複 launchd Label

各 Mac で openclaw doctor --deep --json を取得し、同一 Label が複数 plist に現れていないか、ThrottleIntervalRunAtLoad の食い違いがないかを一覧化します。手早い機械チェックとして grep -R '<key>Label</key>' ~/Library/LaunchAgents /Library/LaunchAgents /Library/LaunchDaemons の値をソートし、重複キーを潰します。正規化の順序は非 canonical を bootout → 単一 plist を bootstrap。退避フォルダに置いた複製が再読込されないよう、拡張子を .disabled に寄せるかパスから外します。

#!/usr/bin/env bash
set -euo pipefail
TENANT="${TENANT:-demo}"
/usr/bin/openclaw doctor --tenant "${TENANT}" --deep --json >"/tmp/oc-deep-${TENANT}.json"
/usr/bin/plutil -lint /Library/LaunchDaemons/com.example.openclaw*.plist 2>/dev/null || true
/usr/bin/printf "deep written: /tmp/oc-deep-%s.json\n" "${TENANT}"

深い巡検のフラグ名は版で揺れ得るため、ヘルプの CLI 節と突き合わせてください。合成プローブに doctor サブチェックを載せる構成はテナント分割稿と同型です。

カナリアポート切片(LB 重みとは別軸)

テナントごとに 8820–8839 のような連番ブロックを予約表に書き、カナリア切片だけ OPENCLAW_GATEWAY_LISTEN や sidecar の --bind をその帯へ載せ替えます。LB が 5% でも、ローカルで別ポートのプロセス束が生きているとヘルス JSON だけが錯覚を起こすため、doctor --deep のポート行と lsof -nP -iTCP の突合を同じ runbook に印刷しておきます。台数と拠点は料金で先に合意すると予約表がブレません。

Webhook 失敗要約のブロードキャスト

通知器ノードが 5 分窓でイベントを畳み、テナント ID・相関 ID・代表 HTTP ステータスを 1 件に要約して送ります。launchd 掃除のあと意図的に 4xx を流し、重複排除が効いているか、degraded が長引くときに要約に理由コードが載るかを確認します。詳細トレースは JSONL、チャットは要約のみ、という二層にすると運用が持ちます。

最小再現ステップ(チェックリスト)

  1. 観測:全ノードで doctor --deep --json を保存し、ホスト名付きで git かオブジェクトストアに集約。
  2. 重複検出Label のソートuniq、ListenURL の衝突表を作る。
  3. 正規化:非 canonical を launchctl bootout、単一 plist のみ bootstrap。plist は事前に cp で退避。
  4. 合成ヘルス/healthz/composite が緑になるまで待機し、合算 readiness と整合。
  5. ポート切片:カナリア帯へ環境変数を載せ替え、curl でローカル疎通。
  6. Webhook ドリル:意図的 4xx→要約 1 件・相関 ID 記載を確認。
  7. 昇格:問題なければ LB 重みを戻すか全ノードへ展開(手順はローリング昇格稿参照)。
  8. 記録:runbook に deep JSON のパスと時刻を残す。

ロールバック(最短)

  1. LB/重み:直前のブックマーク比率へ戻す(カナリア稿の手順と同型)。
  2. ポート:予約表の旧値へ環境変数を戻し、プロセスを再起動。
  3. launchd:退避した plist を元パスへ戻し、誤って二重 bootstrap していないか launchctl list で確認。
  4. 検証doctor --deep を再取得し、掃除前と差分が意図どおりか比較。
  5. 連絡:Webhook 要約チャネルに「巻き戻し完了」と相関 ID を 1 行で投稿。

FAQ(要点)

deep が遅い:メンテ窓・低トラフィック AZ から。タイムアウトは合成プローブで degraded に落とす。要約が二通:窓境界のズレを疑い、通知器の時計と NTP を揃える。

運用ガイド。版差あり—実装フラグで確認。数値は目安で SLA ではありません。
ログイン不要で次の一歩

Mac 網関を足す前に公開情報で合意形成

料金ヘルプ購入ホームはログインなしで閲覧できます。コンソールに入る前にチームで揃えられます。

Mac プランを開く ヘルプへ