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

98 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 数据库迁移重启补充验收
## 结论与范围
北京时间 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 项、零跳过,但不关闭初始化超时、迁移中断临界点或其他生产门禁。