Smail/docs/数据库迁移重启补充验收.md
smail 586f2bca19
Some checks are pending
Security Checks / security (push) Waiting to run
补充SQLite跨引擎实机验收并保留初始化超时反例
2026-09-21 08:18:11 +08:00

8.6 KiB
Raw Blame History

数据库迁移重启补充验收

结论与范围

北京时间 2026 年 9 月 21 日,使用隔离云端实例补充 SQLite 迁移、重启及目标库故障恢复验收,并修复真实发现的 HTTP/HTTPS 重启确认响应丢失问题。本轮未替换 /opt/smail 的正式程序,未清空正式数据库,未停止其他项目或共享数据库服务。

  • [✓] SQLite 迁移失败不覆盖目标,失败后解除写维护状态。
  • [✓] SQLite 迁移后内部重启、系统级进程重启及目标不可读后的恢复。
  • [✓] HTTP/HTTPS 活动响应排空修复与本地、Linux 云端专项复核。
  • [✓] 最新候选 SQLite/MySQL/PostgreSQL 空数据基础回归,配置历史与业务同库。
  • [✓] MySQL/PostgreSQL 同引擎切库后的真实进程重启和故障恢复,见后续补充记录。
  • [✓] MySQL ↔ PostgreSQL 跨引擎应用级迁移、两类重启及账号故障恢复,见 SQL跨引擎迁移补充验收.md。
  • 涉及 SQLite 的四个跨引擎应用级迁移与重启方向。
  • 迁移复制、提交途中进程中断后的恢复。
  • [!] 浏览器、外部收件、自动续期、安全告警、凭据轮换及其他生产门禁仍未关闭。

上述通过项不代表整个项目审计结束,也不是正式实例升级或生产放行。

重启响应缺陷与修复

重启接口交付信号后,主循环立即停止服务。原 HTTP/HTTPS 停服直接调用 http.Server.Close(),可能在响应及会话中间件完成前关闭连接。云端收到 RemoteDisconnected,同时服务日志确认重启请求已经被处理;不能把这种失败按偶发网络问题忽略。

新增统一停服方法:先调用 Shutdown 等待在途响应,期限为 10 秒;超时才强制关闭并保留错误。两种 Web 监听都使用此方法,没有使用任意等待或放宽客户端验收标准。

检查 证据与结果
修复前确定性反例 run-2026-09-20T21-08-10-337Z-39880;HTTP、HTTPS 均提前关闭,客户端 EOF
修复后五轮竞态回归 run-2026-09-20T21-12-58-775Z-4492;通过
五包回归 run-2026-09-20T21-13-36-986Z-3400;HTTP、控制器、重启、数据库迁移、初始化包通过;不宣称可选集成全部零跳过
Linux 云端专项 smail-review-ssl-apex-20260921/20260921-051655-http-restart;六个顶层测试通过、零跳过、退出零
验收器单元测试 test_runtime*.py 共 42 项通过

run-2026-09-20T21-09-33-980Z-37428 保留首次超时测试夹具失败:请求体未消费且缺少独立释放路径,测试服务器清理等待活动请求。确认 PID 后仅停止本轮测试进程;修正夹具后另跑通过,不将夹具错误描述为应用漏洞。

日志名中的 2026-09-20T21...Z 为 UTC,对应北京时间 9 月 21 日。

SQLite 实机证据

最终实例:/var/tmp/smail-review-runtime-20260921-051723/。

本地归档:test-log/production-remediation-20260921/migration-runtime-evidence/smail-review-runtime-20260921-051723/。

  1. 从空库初始化、写入配置历史,真实 SMTP 收信后由 IMAP/POP3 读取中文正文和附件。
  2. 迁移预览后故意占用目标,执行返回 HTTP 409、DATABASE_MIGRATION_TARGET_EXISTS;记录为 failed / TARGET_EXISTS,目标内容未被覆盖。随后配置写入成功,证明维护锁已释放。
  3. 成功迁移至 migrated.db,配置代次推进至 4;等待重启期间业务写入返回 HTTP 503、DATABASE_RESTART_REQUIRED。
  4. API 内部重启返回 accepted,旧 Cookie 会话仍有效;PID 和 InvocationID 不变,这不是进程替换。
  5. systemctl restart 后 PID 和 InvocationID 改变,文件描述符证实仅打开目标业务库,不打开源业务库。
  6. 将本轮目标文件权限改为 000 后再次启动,进程退出码为 1、MainPID 为 0、状态为 failed;配置仍指向目标库,没有静默回退旧库。
  7. 在收尾保障路径恢复目标权限为 0600,重新启动成功。内部重启、系统重启、故障恢复三阶段均验证登录、三种协议认证、旧邮件及新邮件正文和附件。
  8. 新邮件仅写入目标库。源库完整逻辑摘要未变,源配置历史一条、目标一条,kind/id/payload/digest 完整一致。

进程证据:内部重启前后 773001,系统重启后 773123,故障恢复后 773224。

只有 migrated.db 是活动业务数据库;smail.db 和故意占用的 occupied.db 保留为离线证据,不是额外运行数据库,未经许可不删除。

保留两轮云端失败:045727 为验收器未先处理基础回归留下的待重启配置,被正确拒绝;050341 为真实重启响应中断,促成本次应用修复。失败记录均未删除或改成通过。

最新候选的 SQL 基础回归

数据库 隔离实例时间后缀 结果
MySQL 20260921-052137 退出零、基础回归通过、配置历史一条、SQLite 文件零个
PostgreSQL 20260921-052322 退出零、基础回归通过、配置历史一条、SQLite 文件零个

本地证据位于 restart-runtime-evidence/,摘要清单为 restart-evidence-index.json,均在 test-log/production-remediation-20260921/ 下。逐一复核四份下载文件摘要,账号已锁定、数据库桥接已停止,OOM、资源采集错误和清理错误均为零。此处仅为 SQL 基础回归,不包含 SQL 切库进程重启。

最后重新读取六个保护服务状态,PID、InvocationID 与回归前一致,无运行中的 Smail 验收单元。正式程序 SHA-256 仍为 c14ef1c5ba1dc2096c312c8357039a7330c985cbeac90765aed01d8151e05e1f。

构建与可追溯性

版本 review-restart-20260921,构建源码标识 f589f10f0556daeb9437673322d904d17e0a2df2-dirty。restart-source-manifest.json 记录 610 个后端 Go 文件的摘要,restart-build-manifest.json 记录候选产物。

产物 SHA-256
smail-restart 21ec0820f9b09eb1f8262d6d444bbc5d235d4cf64115d6f4b3378be2083533a0
smail-admin-restart 73330cd069570b7bf0181db5497465faad3897eb9b564d3045774bb35bc1472f
http-restart.test d09687338b3f5ded2ff034587292974c975c16e2a09b0595435622125da517ee

本阶段重新编译后端,复用前轮未改动的前端资源和三个 Linux 插件,不声称又完成一次前端重建。拟用的 PowerShell 构建脚本被执行策略拒绝,没有更改策略或执行该脚本,随后使用原生 Go 构建命令;保留的脚本不是实际完整构建成功证据。

静态扫描仅复扫变更的 HTTP 包:九个文件、2,035 行、零告警、零加载错误、退出零,未增加抑制。之前全项目仍有 38 条告警,详见 静态安全告警复核记录.md,不能据此把全项目扫描标为通过。

后续 SQL 迁移补充

北京时间 9 月 21 日 05:37 至 05:45 左右,另建 MySQL、PostgreSQL 隔离源库和目标账号,使用重新编译的候选程序完成同引擎切库、内部重启、系统级进程重启、目标账号不可用时拒绝启动及恢复后的真实邮件读写。三阶段均证明源库活动连接为零、目标库有应用连接,业务与配置历史同库,运行目录没有 SQLite 文件。

完整范围、候选摘要、进程标识、资源与清理结果见 SQL切库与部署回归补充验收.md。前文 052137、052322 两轮仍仅代表当时的 SQL 基础回归,不把后来新增的证据倒填为旧测试已经覆盖。复制/提交途中进程中断与跨引擎应用级矩阵仍待验收。

后续 SQLite 复制中断补充

9 月 21 日 06:17 的新空隔离实例完成未提交复制事务中的 SIGKILL 中断及恢复,随后正常迁移和重启恢复也通过。详见 SQLite复制中断恢复补充验收.md,包含两个夹具失败记录、原始目标及 journal 快照摘要、20 份证据复核与 131 项部署回归。本项仅关闭 SQLite 未提交复制阶段,不关闭提交临界点、配置切换临界点、SQL 数据库中断或跨引擎矩阵。

后续混合引擎矩阵补充

详见 SQLite跨引擎迁移补充验收.md。SQLite → MySQL、SQLite → PostgreSQL、MySQL → SQLite 三个方向通过正式迁移、两类重启、目标不可用及恢复后的读写,三阶段证明只有目标库活动,配置历史同库。

PostgreSQL → SQLite 两次均在空安装恢复码生成请求的 30 秒读取超时处终止,尚未进入迁移;失败原样保留,不能宣称矩阵完整。47 份成功/失败证据及全部测试账号、测试单元和正式服务保护状态已独立复核。最终部署回归 149 项、零跳过,但不关闭初始化超时、迁移中断临界点或其他生产门禁。