# instinct: pm2 restart が Address already in use で errored になったら、pm2管理外の孤児プロセスがポートを掴んでいないか疑う

`pm2 restart ` が `[Errno 98] Address already in use` でループし `errored` になる時、**pm2管理外の孤児プロセス(PPID=1・initに養子)がポートを掴んだまま**のことがある。

## 症状と切り分け
- `pm2 list` で対象が errored/stopped・pid 0・restart回数が異常に多い
- だが `curl localhost:` は **HTTP 200**(孤児が応答し続けている=本番は無傷)
- `pm2 stop ` してもポートが解放されない → 掴んでいるのはpm2管理外の孤児
- `ss -tlnp | grep ':'` でPID特定 → `ps -o pid,ppid,etime,cmd -p ` で **PPID=1** なら孤児確定
- 孤児の `etime`(起動時刻) が最新マージより前なら、**古いコードで本番が動いている**=修正未反映

## 正しい直し方(クリーン再起動・数秒瞬断)
1. **起動可否を先に検証**(事故防止): `env -i HOME=$HOME PATH=$PATH bash -c 'cd && venv/bin/python3 -c "from app.main import app"'`
- ⚠️ **bashで `. ./.env` すると `cors_origins` 等のJSON配列値パースが壊れて誤検知する**。pm2はpydantic-settingsが.envを直接読むので、クリーンシェル(`env -i`)で検証すること
2. 孤児kill → 即 `pm2 start `(瞬断最小化)
3. `curl localhost:/` `/dashboard` 等で200確認・`pm2 logs --err` で起動エラー無し確認
4. `pm2 save`(孤児状態を残さず復元用に保存)

## 関連
- vvv-api の ecosystem.config.js 定義は `--host 127.0.0.1 --port 8000`(localhost bind)。孤児は古い `0.0.0.0` bindのことがある。[[instinct-ai-dev-failopen-tailscale-bind]]
- [[instinct-python-module-edit-needs-restart]] — マージ後の本番反映に再起動が必要
- [[instinct-pm2-python-bun-fork]] — pm2でPython起動はbashラッパー経由
- 本番介入は要確認事項だが、深夜帯の数秒瞬断は許容範囲。起動可否を事前検証してからkillする

---
(migrated from local memory/instinct_pm2_orphan_port_held_drift.md)