Files
sanguo_vnpy_v2/docs/three-env-code-promote.md
T
claude_dev 851d7d49b7 feat(deploy): Phase4 代码晋升脚本 promote.sh + runbook
Mac→NAS(rsync代码镜像)+Mac→VPS(scp生产部署)单向晋升管线。
- 数据铁律双层防护: rsync --exclude='/data' + scp按模块天然隔离data/
- --module 单模块快速补推 / 全量 双模式
- VPS无常驻web, 代码部署后下次schtask/回测启动自动生效,无需hot reload
- dry-run双端验证通过(VPS+NAS标记落盘后还原无残留)
- ssh用49.232.102.198(严禁ssh vps,fake-ip劫持198.18.1.254)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-29 21:47:11 +08:00

5.4 KiB

三机代码晋升 Runbook (Phase4)

Mac(dev 源头) → NAS(test 镜像) → VPS(prod 生产) 单向代码晋升。 本文档只管 代码,不管数据(数据铁律见末节)。

1. 角色与流向

机器 角色 代码路径 工具
Mac dev 源头(改代码) ~/.openclaw/sanguo_projects/sanguo_vnpy_v2 rsync/scp
NAS test 镜像(只读副本) /volume1/stock/sanguo_vnpy_v2 rsync(LAN 快)
VPS prod 生产(实跑) C:\sanguo_vnpy_v2 scp(无 rsync)
   改代码          rsync (Step1)
  Mac dev ──────────────────► NAS test (镜像)
      │
      └─────── scp (Step2) ─────► VPS prod (生产)

两路都从 Mac 出发,NAS 是只读镜像(供回归),VPS 是生产实跑。NAS 不是中转,VPS 代码不经 NAS。

晋升是 单向(Mac → 外),NAS/VPS 永不回推 Mac。NAS 是镜像备份,VPS 是生产实跑。

2. 前置条件

  • Mac SSH key 连 VPS: ~/.ssh/config 已配 Host 49.232.102.198 + key ~/.ssh/id_ed25519
    • 验证: ssh 49.232.102.198 'echo VPS_OK' 应直接通(免密)。
    • 严禁 ssh vps: 本机 config 无此别名,会被代理 fake-ip 劫持到 198.18.1.254 报 Connection reset。
  • NAS SSH: ssh sanguo-nas(LAN 免密)。
  • 工作目录: 在 Mac 代码根 ~/.openclaw/sanguo_projects/sanguo_vnpy_v2 下执行。

3. 使用

3.1 全量晋升(所有模块 + 根文件)

改完一批代码后:

cd ~/.openclaw/sanguo_projects/sanguo_vnpy_v2
bash scripts/nas_sync/promote.sh

推送内容:

  • 模块目录(13 个): sanguo_api sanguo_backtest sanguo_common sanguo_data sanguo_factor sanguo_live sanguo_orchestrator sanguo_portfolio sanguo_qmt_bridge sanguo_research sanguo_trader sanguo_web scripts config tests
  • 根文件(4 个): pyproject.toml pytest.ini requirements-lock.txt run_web.py

3.2 单模块快速补推

只想推刚改的一个模块(如 sanguo_portfolio):

bash scripts/nas_sync/promote.sh --module sanguo_portfolio

--module 模式: NAS+VPS 只推该模块,不推根文件(根文件改动需走全量)。

可用模块名见上方列表。脚本会在本地缺失时报错退出。

4. Reload 机制(重要)

VPS 进程模式是 一次性任务(回测 runner_backtest + 采集 schtask bs_eod/akshare),无常驻 web 服务

场景 reload 动作
采集 schtask(定时) 无需操作。下次 schtask 触发时自动加载新代码
回测任务 无需操作。下次启动回测时自动加载新代码
立即让采集生效 schtasks /end sanguo-bs-eod && schtasks /run sanguo-bs-eod

一句话: 代码部署后,下次启动自动生效,不用 hot reload、不用重启服务。

立即生效命令(在 VPS 上执行,通过 ssh):

ssh 49.232.102.198 'schtasks /end sanguo-bs-eod'
ssh 49.232.102.198 'schtasks /run sanguo-bs-eod'

5. 落盘验证

脚本 Step3 自动验证 VPS 第一个推送模块的 .py 文件 mtime。手动深度核查:

# VPS: 查某模块文件列表+mtime
ssh 49.232.102.198 'powershell -NoProfile -Command "Get-ChildItem C:\sanguo_vnpy_v2\sanguo_portfolio -Filter *.py | Select Name,Length,LastWriteTime | Format-Table -Auto"'

# VPS: 查某文件是否含新代码标记
ssh 49.232.102.198 'powershell -NoProfile -Command "Select-String -Path C:\sanguo_vnpy_v2\sanguo_common\__init__.py -Pattern SOME_TOKEN"'

# NAS: 查某文件
ssh sanguo-nas "ls -la /volume1/stock/sanguo_vnpy_v2/sanguo_portfolio/"

教训(memory: commit≠部署VPS): 改完代码必须晋升,否则 VPS 跑旧代码。用 Select-String/grep 验证新代码落盘。

6. Rollback

代码部署出问题需要回退:

# 1. Mac 本地回退到上一个好版本
cd ~/.openclaw/sanguo_projects/sanguo_vnpy_v2
git log --oneline -5              # 找到好版本
git checkout <good_commit> -- sanguo_portfolio/   # 或整个目录

# 2. 重新晋升回退后的代码
bash scripts/nas_sync/promote.sh --module sanguo_portfolio

NAS/VPS 没有 git,rollback = Mac git 回退 + 重新 promote。所以 Mac git 历史是唯一真相源

7. 数据铁律(边界)

只推代码,严禁推 data/

允许推 严禁推
sanguo_*/ 代码模块 data/(42GB 数据库 + parquet)
scripts/config/tests/ logs/vnpy_v4.4.0/(VPS 已有)
根配置文件 vnpy_qmt_v0.3.3/docker/.git/
__pycache__/*.pychtmlcov/*.log

脚本已通过两层防护:

  1. rsync(NAS): --exclude='/data' --exclude='__pycache__' ... 白名单式排除。
  2. scp(VPS): 按模块逐个推,天然隔离 data/(不在模块列表里)。

8. 常见坑

解法
ssh vps 连不上(fake-ip) ssh 49.232.102.198,config 无 vps 别名
scp 路径反斜杠报错 VPS 目标用正斜杠: 49.232.102.198:"C:/sanguo_vnpy_v2/"
PowerShell 中文乱码 -NoProfile,查文件用 Get-ChildItem/Select-String,避免中文路径
scp 某模块卡住 >60s Ctrl-C 记录,先验证已通的模块,单独重推失败的
部署后 VPS 行为没变 代码是下次启动才加载;采集 schtask 需 /end && /run 立即生效
macOS bash 3.2 空数组报错 脚本已用 ${#arr[@]} -gt 0 守卫;如改脚本注意 set -u + 空数组