姚章浩
|
3f603aa293
|
feat(backup): 系统设置里的存储与备份——定时时间与储存天数可配、下发到目标主机 cron
需求:整库逻辑备份做定时,但要在「系统设置 → 存储与备份」里设置定时时间与储存天数。
后端
- migration 000045 backup_schedule(单行:enabled/schedule_time/retention_days/retention_months/
last_applied_*),store + 领域校验(HH:MM、1~365 天、0~24 月,非法值 400 且不落库不下发)
- internal/backuphost:通过 ssh 在目标主机上读回/下发计划并立即备份(未接线时 Available=false,
页面降级提示;主机侧错误带输出回传)。最近一次只认有 MANIFEST.json 的完整目录,跳 *.incomplete
- 接口 GET/PUT /api/v1/backup-schedule、GET …/host、POST …/apply、POST …/run;
写操作经 classifyRole 限管理员;run 为异步 202 + 在途单飞(http 写超时 30s,备份约 35s)
- openapi.yaml 补齐 5 条路由(契约测试要求每条都写 400/500)
主机侧
- scripts/install_backup_schedule.sh(幂等):写 /etc/knowledge-governance/backup-schedule.env 与
/etc/cron.d/kb-logical-backup,参数校验,--show/--disable,最后一行 SCHEDULE_APPLIED 供平台核对
- logical-backup.sh 从该文件读保留策略;失败或被中断把目录改名 *.incomplete,不留'像成功'的半成品
- install --show 只回显计划行(原先把 SHELL=/PATH= 当计划显示)
前端
- web/src/backupSchedule.ts(严格解析:缺计划字段即报错,不把默认值伪装成设置)
- BackupScheduleSection:容器 + 纯视图(管理员表单/只读、已一致/待下发、在途轮询)
运行前提(已落实):运行镜像加 openssh-client,且容器 uid 1000 在 /etc/passwd 有名字
(否则 ssh 报 No user exists for uid 1000);凭据只读挂载 secrets/backup-host(git 忽略)
实测:主机 cron 每天 03:30 / 保留 7 天 / 每月 3 份;立即备份一次 34 秒 / 742.7 MiB / 失败 0;
Go 与前端测试全绿(170 vitest)。
|
2026-10-09 13:50:23 +08:00 |
|
姚章浩
|
4455d02262
|
test(backup): 留档回填演练脚本 + 实测通过
scripts/restore_drill.py:把留档 PG 行按原文 \copy FROM 回填进目标库,核对每张表行数与清单、
抽样页面正文/标题逐字段比对,再用临时跟踪表 _drill_restored 精确删除并断言残留为 0。
实测(本地测试库 weknora_full,留档 20261009T041913Z-0b217e8a):13,539 行全部回填成功、
8 张表行数与清单逐一致、冲突 0、抽样页正文一致(388 字符)、残留 0。
同时记录一个格式事实:留档 JSONL 是 psql \copy text 格式(转义),按行 json.loads 会失败
(knowledges 3830/3830、wiki_pages 218/1982),回填/程序化读取须先按 text 格式反转义。
|
2026-10-09 13:07:41 +08:00 |
|
姚章浩
|
19e0596e1d
|
fix(backup): 整库逻辑备份按库容错,默认跳过 RDS 管理库 rdsadmin
单库 pg_dump 失败(权限/编码/管理库)不再中止整次备份:清掉半个目录、记进 MANIFEST.failed_databases、
轮转照常执行、最后按失败情况给退出码。云主机实跑:33 秒 / 742.6 MiB / 8 库 / 失败 0。
|
2026-10-09 12:25:12 +08:00 |
|
姚章浩
|
a1be19bb0f
|
docs(backup): 补实测耗时(2m52s 快路径 / 19m40s 含 ES 回传)与 ES 导出哈希非确定性判据
|
2026-10-09 12:22:55 +08:00 |
|
姚章浩
|
b32755b35f
|
feat(backup): 备份目录契约 + 导入前留档覆盖 ES 层
- scripts/backup_layout.sh:定义 $KB_BACKUP_ROOT/{target-kb-snapshots,rds-logical,es-snapshots,logs}
与 /etc/knowledge-governance/backup.env,任意主机跑同一份(测试云主机 → 未来生产云主机)
- scripts/es_kb_export.py:只读 scroll 导出目标库 ES 文档(gzip JSONL,_id/_source,可按 _id 重建)
- scripts/target_kb_snapshot.sh:留档改为 PG 行 + ES 文档两层;PULL_ES 默认 0(692 MB / 家用上行 19m40s,
留在目标主机,清单记 location=cloud:<host>:<path>);挂载源与落点统一走 KB_BACKUP_ROOT
- scripts/logical-backup.sh:自管整库逻辑备份(pg_dump -Fd -j4 -Z6,按天轮转)
- internal/releasesnapshot:门禁要求 PG 与 ES 两层齐备(ES 计数 >0);云侧留档核声明与哈希、
声明本地却缺失则 fail-closed;新增 3 条用例(共 10)
- cmd/guardcheck:用真实产物复核门禁判断
- docs:PRODUCTION_BACKUP_RECOVERY.md 重写(契约/RDS 控制台/恢复路径/边界);P6 同步留档语义
|
2026-10-09 12:19:15 +08:00 |
|
姚章浩
|
6f16c3af20
|
fix(compose): 快照目录挂载并入 release-worker 既有 volumes 列表
build / build (push) Successful in 34s
上一版把 volumes 写成了重复键(compose 解析失败),并且误删了 extra_hosts/
networks。现在合并成一份挂载列表,端点别名(prod-pg/prod-es/prod-weknora)
保持不变;容器内已核对:快照目录可见、target_snapshot 配置已加载。
另新增 docs/PRODUCTION_BACKUP_RECOVERY.md:五层备份现状(PG 行级快照 /
发布前硬门禁 / ES 快照仓 + SLM / OSS 版本控制 / RDS 待确认)、RDS 控制台清单、
按事故类型的恢复路径与耗时、以及每次发布前的标准动作。
|
2026-10-09 11:02:32 +08:00 |
|