Files
memind/docs/service-isolation-runbook.md
T

9.4 KiB
Raw Blame History

隔离说明:这份文档只讲生产 / 测试 / 预览边界和事故恢复,不是本地联调手册。要做本机开发,请看 docs/local-dev.md

生产 / 测试 / 预览隔离规程

这份文档的目标只有一个:开发预览不能再影响生产。

端口边界

环境 目录 用途 端口
生产 /Users/john/Project/Memind g2.tkmind.cn 当前在线服务(阿里云解析 → 105 → 本机 Mac) 8081
生产 Plaza /Users/john/Project/Memind + Plaza plaza.tkmind.cn 当前在线服务 3001
生产入口 /Users/john/Project/Memind/scripts/g2-lb.Caddyfile 105 转发入口 / 反代配置 8090
测试 Portal /Users/john/Project/Memind 开发预览 API / Portal 18081
测试 Vite /Users/john/Project/Memind 开发预览前端 15173
测试 Admin /Users/john/Project/Memind 开发预览后台 18082
测试 Plaza /Users/john/Project/Memind 开发预览 Plaza 13001
测试 Ops /Users/john/Project/Memind 开发预览 Ops 13002

硬规则:

  • 不在开发预览中使用 808130018090
  • 禁止 SSH 到 105 直接改业务源码;105 是入口/代理层,变更须本地 commit 后发布。见 105 服务器变更规范
  • 不在生产目录里跑会清理端口的开发脚本。
  • 不执行 scripts/install-prod-services.sh 来做开发预览;它会释放生产端口。
  • 不手动 kill 8081 上的进程,除非目标就是恢复/重启生产,并且已经确认影响窗口。

Harness 角色边界

Harness 是开发工具层,不是生产服务层。

正确关系:

Codex / Cursor / Goose 开发过程
        -> harness 记忆、recall、context pack、审计
        -> Memind / tkmind_go 开发
        -> 测试通过后发布到生产

禁止关系:

g2.tkmind.cn 生产请求
        -> 必须依赖 harness 才能运行

本机已有全局 harness

/Users/john/Project/harness

它应该嵌入 Codex、Cursor 这类开发工具,让项目开发有记忆:

/Users/john/Project/harness/bin/codex-harness
/Users/john/Project/harness/bin/install_cursor_hooks.sh
/Users/john/Project/harness/bin/start_dashboard.sh

开发时按项目目录区分记忆上下文:

项目目录 记忆含义
/Users/john/Project/Memind 生产项目的开发记忆
/Users/john/Project/Memind 测试项目的开发记忆
测试 Goose 项目目录(按本机实际路径填写) 测试 Goose 的开发记忆

硬规则:

  • 生产启动脚本不能依赖 harness 才能启动。
  • 生产请求链路不能调用 harness 才能响应。
  • 测试开发可以使用 harness,但不能写入或覆盖生产运行数据。
  • 如果要做测试专用长期记忆,优先放在 /Users/john/Project/test/harness 或明确的 test 项目命名空间。

当前生产如何确认

只读检查:

cd /Users/john/Project/Memind
lsof -nP -iTCP:8081 -sTCP:LISTEN
curl -s http://127.0.0.1:8081/api/status
cat .h5.pid

期望:

  • 8081node server.mjs 监听。
  • /api/status 返回 ok
  • .h5.pid 指向当前生产进程。

不要用下面这些命令做普通预览:

pnpm dev
pnpm dev:server
pnpm start
pnpm start:plaza
node scripts/dev.mjs
node server.mjs
scripts/install-prod-services.sh

这些命令如果没有端口隔离,可能占用或释放生产端口。

下次开发要预览,怎么做

优先在测试目录进行:

cd /Users/john/Project/Memind

启动前先确认生产还在:

curl -s http://127.0.0.1:8081/api/status
lsof -nP -iTCP:8081 -sTCP:LISTEN

再用测试端口启动预览:

H5_PORT=18081 \
VITE_PORT=15173 \
ADMIN_PORT=18082 \
PLAZA_PORT=13001 \
OPS_PORT=13002 \
H5_PUBLIC_BASE_URL=http://127.0.0.1:15173 \
VITE_MINDSPACE_BASE=http://127.0.0.1:15173 \
pnpm dev

访问地址:

页面 地址
H5 预览 http://127.0.0.1:15173/?preview=mindspace
测试 Portal http://127.0.0.1:18081/api/status
测试 Admin http://127.0.0.1:18082/healthz
测试 Plaza http://127.0.0.1:13001/plaza
测试 Ops http://127.0.0.1:13002/ops/

如果只改前端样式,优先只启动 Vite:

cd /Users/john/Project/Memind
VITE_PORT=15173 \
H5_PUBLIC_BASE_URL=http://127.0.0.1:15173 \
VITE_MINDSPACE_BASE=http://127.0.0.1:15173 \
pnpm dev:vite -- --host 127.0.0.1 --port 15173

这种方式不会碰 8081,适合做 UI 预览。

Goose 测试服务

生产 Goose 端口当前不要复用。测试 Goose 放在:

/Users/john/Project/test/test_tkmind_go

测试 Goose 端口建议固定为:

用途 端口
测试 goosed A 18106
测试 goosed B 18107

测试 H5 如果要连测试 Goose,必须在测试目录 .env 中显式设置对应地址,不能指向生产 Goose。

goosed extension 堆积与文件句柄告警

如果 H5 / MindSpace 侧出现下面这类错误:

会话策略同步失败:{"message":"Failed to add extension: IO error: Too many open files (os error 24)"}

先不要直接重启生产服务。这个报错在本机更常见的含义是:

  • goosed agent 下面堆积了过多旧的 extension 子进程。
  • macOS launchctl limit maxfiles 软上限偏低时,/agent/add_extension 会先撞到文件句柄上限。
  • 如果恢复会话时无条件重启 agent,会把旧子进程堆得更快。

先做只读确认:

launchctl limit maxfiles
lsof -nP -iTCP -sTCP:LISTEN | rg '18006|18007|8081|3001|8090'
for pid in 51613 51657; do
  echo "PID $pid $(ps -p $pid -o command=)"
  lsof -n -p $pid 2>/dev/null | wc -l
done
ps -axo pid,ppid,etime,command | rg 'mindspace-sandbox-mcp|mcp-server-fetch|goosed agent'

判断口径:

  • 808130018090 正常监听,说明主站未必有故障。
  • 如果某个 goosed agent 的 FD 数已经逼近或超过 256,优先怀疑 extension 子进程堆积。
  • 如果同一个 MindSpace/<id> 在同一个 goosed 父进程下出现多个 mindspace-sandbox-mcp.mjs,通常只应保留最新一个。

安全处理顺序:

  1. 先确认主站端口 808130018090 正常,不要把 route 问题误判成全站宕机。
  2. 不先杀 goosed agent 主进程,也不要碰 8081 上的 server.mjs
  3. 优先只清理同父进程、同 MindSpace/<id> 下重复堆积的旧 mindspace-sandbox-mcp.mjs 子进程,以及重复的旧 mcp-server-fetch 子进程。
  4. 清理后立刻复查 18006 / 18007/statusgoosed FD 数,确认 agent 仍存活。

这次线上排查的经验值:

  • 两个 goosed agent 的 FD 数曾达到 263 / 209,而 launchctl limit maxfiles 软上限是 256
  • 仅清理重复 extension 子进程后,FD 数降到 96 / 771800618007/status 仍为 ok
  • 代码层已改为仅在会话策略真正变化时才触发 agent 重启,减少恢复会话时继续堆积 extension 子进程的概率。

自动巡检:

  • scripts/monitor-goosed-fds.mjs 每次检查 goosed agent FD 数和 mindspace-sandbox-mcp.mjs 子进程数。
  • scripts/install-goosed-monitor.sh 会安装 ~/Library/LaunchAgents/cn.tkmind.goosed-monitor.plist,默认每 60 秒运行一次。
  • 默认策略只清理:
    • orphan 的 sandbox MCP 子进程;
    • 同一父进程、同一 MindSpace/<id> 下超过 2 个的重复 sandbox MCP
    • 总 sandbox MCP 数超过 80 时最旧的一批。
  • 默认不按存活时间清理单个老进程,避免误伤长会话。
  • goosed FD 超过 GOOSED_FD_WARN=180 只记录 warning;超过 GOOSED_FD_RESTART=3200 才滚动重启对应 goosed。

硬规则:

  • 不要因为 Too many open files 先去重启 8081 生产 Portal。
  • 不要在未确认影响窗口前直接重启 goosed agent 主进程。
  • 优先清理“明显重复”的 extension 子进程,而不是清空所有 agent 子进程。

数据库口径

短期如果沿用同一个 RDS 库,只允许做 UI 和非破坏性流程预览。

不能在共用库时做这些事:

  • 改表结构。
  • 跑迁移脚本。
  • 批量清理数据。
  • 测试支付回调、发布审核、权限变更等会污染真实用户状态的流程。

涉及数据结构或真实业务状态的开发,先建独立测试库,再预览。

发布前流程

完整步骤、分步发布、105 同步与回滚见 生产更新发布指南

最小检查:

  1. 在测试端口(如 18081)完成开发与预览;本机联调目录请看 docs/local-dev.md,不要把这份规程当成开发启动手册。
  2. pnpm run build + pnpm test
  3. curl -s http://127.0.0.1:8081/api/status 确认生产仍在线。
  4. ./rsync_to_server.sh --dry-run 预览 diff,确认后再执行正式发布。

事故恢复最小步骤

如果发现 g2.tkmind.cn 异常,先检查本地主机生产:

cd /Users/john/Project/Memind
lsof -nP -iTCP:8081 -sTCP:LISTEN
curl -s http://127.0.0.1:8081/api/status

如果 8081 没有监听,再恢复本地主机 Portal:

cd /Users/john/Project/Memind
nohup /opt/homebrew/opt/node@24/bin/node server.mjs >> h5.log 2>&1 &
echo $! > .h5.pid
sleep 2
curl -s http://127.0.0.1:8081/api/status

恢复后再检查入口反代:

curl -s http://127.0.0.1:8090/api/status