Add db ops to svc.sh: port change, backup, restore, clone, cross-instance copy #59

Merged
weichen merged 3 commits from feature/svc-db-ops into main 2026-09-30 14:12:07 +00:00
Owner

feature/svc-db-ops 任务卡

任务主记录:<PR 链接,task-finish 时填写>;状态:进行中;owner:weichen

基线与授权

  • 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= d54bfdd8e9
  • 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-svc-db-ops(worktree);分支:feature/svc-db-ops
  • 授权与交付终点:用户确认方案后授权实施 svc 数据库运维扩展;终点 = 实现合入 main 并回收工作区。
    仅改 Dev 仓 scripts/svc.sh(及 Makefile 帮助行);不碰主检出 .video_agent/(已本地 exclude)。
  • 主记录 PR 链接:<task-finish 时回填>

目标与非目标

目标(scripts/svc.sh 数据库运维扩展,均沿用既有登记/事件/安全边界):

  1. set <name> [--port N] [--host H] [--apply] [--tag T...]:显式变更登记。postgres 换端口
    运行中须 --apply(stop→改登记→start);未运行直接生效;端口冲突预检(登记+监听双查)。
    agent/static 的 set 只改 tags(换端口走 restart --port)。
  2. db backup <name> [--db X] [--out F]:pg_dump -Fc → runtime//backups/-.dump
    (600),pg_restore --list 自校验;db backups 列表。
  3. db restore <name> --file F [--db X] [--force]:恢复;目标库非空拒绝覆盖,--force 才
    DROP WITH (FORCE)+重建+恢复;完成后回显表数。
  4. db clone <src> <dst> [--port P] [--password PW] [--tag T] [--online]:默认物理克隆
    (短暂停源→cp -a pgdata→登记目标(新端口/继承用户库认证)→复启源;目标不自动启动);
    --online 走 dump/restore 不停源(目标须已 create+start)。
  5. db copy <src> <dst> [--db X] [--force]:跨实例单库逻辑复制(双方须运行;目标非空须 --force)。
  6. db ls <name>:列出实例内数据库。

非目标:agent SQLite 备份(本轮不做,记剩余项);不做定时/增量备份;不做跨主机传输;
restore/clone 不删除备份文件;不动后端二进制(无 migrate 子命令,迁移=数据搬运)。

同步记录

节点 sync_base_sha tested_head_sha checked_at
启动 d54bfdd8e9 d54bfdd8e9 2026-09-30T14:01:04Z

关键实现约定

  • 显式参数 psql/pg_dump/pg_restore 助手(不依赖全局 ENV_*),支持 clone/copy 双实例切换;
  • svc.env 单键改写(svc_set_key)先读后写,避开"重定向块内读同文件"截断陷阱;
  • 备份/克隆/搬库全部进 history.jsonl;restore/copy 的覆盖必须 --force;
  • 物理克隆复用既有"只停自己进程"约束;复制剔除 postmaster.pid/.opts,socket 目录(-k)
    本就在环境目录而非 pgdata,不随 cp 传播。

结果与验证(完成后填写)

  • 结果:svc.sh 新增数据库运维族:set(换端口/标签,运行中须 --apply)、db backup/backups/ restore(pg_dump -Fc + 归档自检 + --force 覆盖防护)、db clone(默认物理:短暂停源→
    cp pgdata→登记目标→复启源;--online 不停源)、db copy(跨实例单库,--force 防护)、
    db ls;显式参数 pg_run/dump/restore 助手、svc_set_key 单键改写、check_port_available。
    Makefile 帮助行同步。
  • 验证(真实 postgresql@18,全部在任务工作区 runtime 内;进程已停、目录已清):
    • 备份→backups 列表→归档自检;坏文件 restore 被拒(非 pg_dump 归档)。
    • set:运行中无 --apply 拒绝;--apply 后旧端口释放/新端口监听/DSN 联动/数据完整(3 行)。
    • 物理克隆:源短暂停止→复制→源在自身端口复启→目标 8896 启动后双实例数据一致;
      测试中发现并修复 CLI --port 泄漏进源复启的 bug(clone/copy 入口清空地址覆盖)。
    • copy:空目标成功;目标非空拒绝;--force 覆盖后行数与源一致(自动生成密码实例亦验证)。
    • restore:新库成功(回显表数);再恢复同库拒绝;--force 成功。
    • --online 克隆:源 pid 全程不变,目标数据一致。
    • set --tag 合并去重;list --tag 过滤;history 记录 backup/restore/clone/copy/set 事件。
    • 错误路径:目标已存在/端口被登记占用/坏归档/非 postgres 服务均明确报错。
  • 影响与剩余项:agent/static 的 SQLite/静态资源备份未做(登记为后续项);定时/增量备份不在
    本轮;restore --force 的 DROP WITH (FORCE) 需 PG13+(宿主 18 满足)。
# feature/svc-db-ops 任务卡 任务主记录:<PR 链接,task-finish 时填写>;状态:进行中;owner:weichen ## 基线与授权 - 权威仓:ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git;目标分支:main;R0(initial_base_sha)= d54bfdd8e99d5d3d9a7f5b1db65ab90c841dd7e0 - 工作区:/home/weichen/projects/Agent-System-Dev-wt-feature-svc-db-ops(worktree);分支:feature/svc-db-ops - 授权与交付终点:用户确认方案后授权实施 svc 数据库运维扩展;终点 = 实现合入 main 并回收工作区。 仅改 Dev 仓 `scripts/svc.sh`(及 Makefile 帮助行);不碰主检出 .video_agent/(已本地 exclude)。 - 主记录 PR 链接:<task-finish 时回填> ## 目标与非目标 目标(scripts/svc.sh 数据库运维扩展,均沿用既有登记/事件/安全边界): 1. `set <name> [--port N] [--host H] [--apply] [--tag T...]`:显式变更登记。postgres 换端口 运行中须 --apply(stop→改登记→start);未运行直接生效;端口冲突预检(登记+监听双查)。 agent/static 的 set 只改 tags(换端口走 restart --port)。 2. `db backup <name> [--db X] [--out F]`:pg_dump -Fc → runtime/<name>/backups/<ts>-<db>.dump (600),pg_restore --list 自校验;`db backups` 列表。 3. `db restore <name> --file F [--db X] [--force]`:恢复;目标库非空拒绝覆盖,--force 才 DROP WITH (FORCE)+重建+恢复;完成后回显表数。 4. `db clone <src> <dst> [--port P] [--password PW] [--tag T] [--online]`:默认物理克隆 (短暂停源→cp -a pgdata→登记目标(新端口/继承用户库认证)→复启源;目标不自动启动); --online 走 dump/restore 不停源(目标须已 create+start)。 5. `db copy <src> <dst> [--db X] [--force]`:跨实例单库逻辑复制(双方须运行;目标非空须 --force)。 6. `db ls <name>`:列出实例内数据库。 非目标:agent SQLite 备份(本轮不做,记剩余项);不做定时/增量备份;不做跨主机传输; restore/clone 不删除备份文件;不动后端二进制(无 migrate 子命令,迁移=数据搬运)。 ## 同步记录 | 节点 | sync_base_sha | tested_head_sha | checked_at | |---|---|---|---| | 启动 | d54bfdd8e99d5d3d9a7f5b1db65ab90c841dd7e0 | d54bfdd8e99d5d3d9a7f5b1db65ab90c841dd7e0 | 2026-09-30T14:01:04Z | ## 关键实现约定 - 显式参数 psql/pg_dump/pg_restore 助手(不依赖全局 ENV_*),支持 clone/copy 双实例切换; - svc.env 单键改写(svc_set_key)先读后写,避开"重定向块内读同文件"截断陷阱; - 备份/克隆/搬库全部进 history.jsonl;restore/copy 的覆盖必须 --force; - 物理克隆复用既有"只停自己进程"约束;复制剔除 postmaster.pid/.opts,socket 目录(-k) 本就在环境目录而非 pgdata,不随 cp 传播。 ## 结果与验证(完成后填写) - 结果:svc.sh 新增数据库运维族:`set`(换端口/标签,运行中须 --apply)、`db backup/backups/ restore`(pg_dump -Fc + 归档自检 + --force 覆盖防护)、`db clone`(默认物理:短暂停源→ cp pgdata→登记目标→复启源;--online 不停源)、`db copy`(跨实例单库,--force 防护)、 `db ls`;显式参数 pg_run/dump/restore 助手、svc_set_key 单键改写、check_port_available。 Makefile 帮助行同步。 - 验证(真实 postgresql@18,全部在任务工作区 runtime 内;进程已停、目录已清): - 备份→backups 列表→归档自检;坏文件 restore 被拒(非 pg_dump 归档)。 - set:运行中无 --apply 拒绝;--apply 后旧端口释放/新端口监听/DSN 联动/数据完整(3 行)。 - 物理克隆:源短暂停止→复制→源在自身端口复启→目标 8896 启动后双实例数据一致; 测试中发现并修复 CLI --port 泄漏进源复启的 bug(clone/copy 入口清空地址覆盖)。 - copy:空目标成功;目标非空拒绝;--force 覆盖后行数与源一致(自动生成密码实例亦验证)。 - restore:新库成功(回显表数);再恢复同库拒绝;--force 成功。 - --online 克隆:源 pid 全程不变,目标数据一致。 - set --tag 合并去重;list --tag 过滤;history 记录 backup/restore/clone/copy/set 事件。 - 错误路径:目标已存在/端口被登记占用/坏归档/非 postgres 服务均明确报错。 - 影响与剩余项:agent/static 的 SQLite/静态资源备份未做(登记为后续项);定时/增量备份不在 本轮;restore --force 的 DROP WITH (FORCE) 需 PG13+(宿主 18 满足)。
weichen added 3 commits 2026-09-30 14:11:48 +00:00
Why:
The service manager could create and run postgres instances but had no
way to retarget a port explicitly, back data up, clone an instance to
another port, or move a database between instances — the user asked for
exactly these operations.

Evidence:
- "set <name> [--port N] [--host H] [--apply] [--tag T...]": explicit
  registration change; running postgres requires --apply (stop → rewrite
  registration → start); port availability checked against both
  registrations and live listeners. Verified: 8890→8895 with data intact
  and DSN updated, old port freed; refusal without --apply.
- "db backup <name> [--db X] [--out F]": pg_dump -Fc into
  runtime/<name>/backups/ (0600) with pg_restore --list self-check;
  "db backups" lists them.
- "db restore <name> --file F [--db X] [--force]": restores into a new db
  or refuses on a non-empty target unless --force (drop with FORCE +
  recreate + restore), reporting table counts afterwards. Verified all
  three paths.
- "db clone <src> <dst> [--port P] [--password PW] [--tag] [--online]":
  default physical clone (brief source stop, cp -a of pgdata minus
  postmaster files, new registration, source restarted on its own port);
  --online copies via dump/restore without stopping the source (verified
  source pid unchanged). Clone lands on the requested or derived port.
- "db copy <src> <dst> [--db X] [--force]": single-database logical move
  between two running instances with the same non-empty-target guard.
  "db ls <name>" lists databases.
- Fixed during verification: clone/copy leaked the CLI --port into the
  source restart path (source briefly came up on the clone's port); the
  address overrides are now cleared inside those commands.

Impact:
All operations stay inside runtime/<name>/, append to history.jsonl, and
reuse the existing safety constraints (own-process stop, port conflicts
reported not seized, secrets in 0600 files). Overwriting a non-empty
database requires an explicit --force everywhere. Makefile help line
mentions the new db subcommands.

Refs: .task/feature-svc-db-ops.md(任务卡=PR 描述)
Record the sync checkpoint
ci / test (pull_request) Failing after 1m40s
9bbbdf22ac
weichen merged commit 30a09686ea into main 2026-09-30 14:12:07 +00:00
Sign in to join this conversation.
No Reviewers
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: weichen/Agent-System-Dev#59