refactor: 备份/恢复改为「SQLite 归档 + 单事务整库替换」——不再换文件,也不再依赖 SQLite 运行时
SQLite 从"运行时数据库"降级为"备份交换格式":导出把当前库(MySQL 或 SQLite)
整库写成一份 SQLite 归档,恢复则是启动时在单个事务里 DELETE + INSERT。
前端三个接口的契约一行未改。
- core/system_backup.py 重写:
* dump_to_sqlite()(旧名 snapshot_db 保留为别名)取代在线备份 API:MySQL 下把
这条连接提到 REPEATABLE READ,保证 12 张表读的是同一时刻
* zip 结构不变(users.db + manifest.json + apks/),既有老备份继续可导入;不依赖
任何外部二进制(sqlite3 是标准库,python:slim 容器里现成)
* manifest 增加 db_backend / deployment_env / source_db_id,用于识别备份来源环境
* apply_restore:安全网从裸 pre_restore_*.db 升级为 pre_restore_*.zip(可直接再导入
回滚);跨环境导入默认硬停(需 force_env_mismatch=true)
* consume_pending_restore:启动时单事务整库替换,任何一步失败 rollback,当前数据
完好(比换文件更安全);坏归档挪 restore_failed_* 且不阻塞启动
* 归档库收尾时 checkpoint 回单文件模式并清掉 -wal/-shm(zip 只打包主文件)
- web_server.py:consume 从 init_db 之前移到之后(现在是事务替换,需要表与 app context)
- config.py:BACKUP_DIR / RESTORE_STAGING_DIR / RESTORE_PENDING_DIR 支持环境变量覆盖
—— 自动化测试必须把恢复目录指到临时位置,否则测试造的"待生效恢复任务"会在服务
下次重启时被当成用户的操作消费掉
- core/db_config.py:SQLite 回退模式也写库环境标签(备份要能标出来源环境)
- web/system_api.py + static/admin/system.js + templates/admin/monitor.html:
预览显示来源/当前环境,跨环境时出现「允许跨环境导入」勾选项;文案同步
验证(隔离副本,绝不碰真实库):导出→zip 结构与 manifest 正确;预览带来源环境与
告警;应用→生成 pre_restore zip + 归档就位;跨环境 apply 被拒;模拟重启→数据回到
导出时刻、经验库/动作库完好;塞入坏归档→挪 restore_failed_*、服务照常启动、数据未变。
This commit is contained in:
@@ -930,10 +930,11 @@ body{background:var(--bg);font-family:var(--body);color:var(--text);font-size:14
|
||||
<!-- 子分栏 1:数据备份 -->
|
||||
<div class="sub-panel active" id="system-sub-backup">
|
||||
<div class="help">
|
||||
<b>导出</b>当前系统数据为 zip:含 <code>users.db</code> 在线一致快照(<b>全部业务表</b>:用户 / 任务计划 / 设备分组 /
|
||||
<b>导出</b>当前系统数据为 zip:把数据库(MySQL 或回退模式的 SQLite)整库一致快照成
|
||||
<code>users.db</code> 归档(<b>全部业务表</b>:用户 / 任务计划 / 设备分组 /
|
||||
自定义动作 / APK 记录 / 设备池 / 待连接设备 / AI 会话 / 经验库 / 经验巡检 / <b>动作库</b> / 系统配置)+ 可选的
|
||||
<code>apks/</code> 应用文件。恢复用:换机 / 整库迁移 / 出问题前留底。
|
||||
<br><span class="text-muted">清单见预览的「表数据行数」;新增持久化表须登记进备份覆盖清单(红线,见 doc/DEPLOY.md §5.2)。</span>
|
||||
<br><span class="text-muted">清单见预览的「表数据行数」(由模型元数据自动派生,新增表不会漏);备份里记录了来源环境,跨环境导入默认拒绝。</span>
|
||||
</div>
|
||||
<div class="toolbar" style="gap:8px">
|
||||
<label style="display:inline-flex;align-items:center;gap:4px;margin:0 6px">
|
||||
@@ -951,7 +952,9 @@ body{background:var(--bg);font-family:var(--body);color:var(--text);font-size:14
|
||||
<div class="sub-panel" id="system-sub-restore">
|
||||
<div class="help">
|
||||
<b>导入恢复</b>:上传平台导出的 <code>.zip</code> 或 <code>.db</code> → 先<b>校验预览</b> →
|
||||
确认后系统会<b>自动备份当前库</b>并把恢复任务挂起,<b>重启 web_server 后生效</b>(导入将覆盖现有全部数据)。
|
||||
确认后系统会<b>自动备份当前库</b>(<code>data/backups/pre_restore_*.zip</code>,可直接再导入回来)并把恢复任务挂起,
|
||||
<b>重启 web_server 后生效</b>(导入将覆盖现有全部数据;数据替换在单个事务里完成,失败会自动回滚)。
|
||||
<br><span class="text-muted">备份来自另一个环境(dev↔prod)时默认拒绝导入,需在预览页显式勾选「允许跨环境导入」。</span>
|
||||
</div>
|
||||
<div class="toolbar" style="gap:8px">
|
||||
<input type="file" id="restore-file" accept=".zip,.db">
|
||||
|
||||
Reference in New Issue
Block a user