Go 28:进程重启后任务记录能说明什么
上篇给 HTTP 路径上的数据库等待设置期限,仍没有处理进程突然消失的情况。SQL 里留下 RUNNING,只能说明某次领取已提交;进程死后,它不可能自己变成终态。QUEUED 留着原文,倒是可以由后续启动的 worker 再领取。本篇继续修改同一个任务服务,区分这两行的恢复动作。完整累计工程、SHA-256和独立解包步骤可复跑真实子进程实验。
先看进程死时数据库实际保存了什么
测试在隔离的 PostgreSQL 16.15 上启动一个独立 Go 子进程,提供原有 POST /tasks、GET /tasks/{id},worker 数为 1,排队槽位为 1。连续提交 task[0] 和 task[1] 都得到 HTTP 202。第一个 worker 已把 task[0] 从 QUEUED 条件更新为 RUNNING,并进入故意不退出的分析器;第二个仍是 QUEUED。父进程查到这两行后调用 os.Process.Kill,Wait 确认子进程被信号终止。它没有机会执行 service.Close,不能把正常关闭时的等待语义套到这里。
杀死进程后再次从数据库查询,task[0] 仍是 RUNNING。PostgreSQL 16 的事务文档说明,数据库报告完成的事务会留下持久记录;本轮实测只观察到应用进程退出后的数据库状态,没有模拟数据库掉电。HTTP 202 表示先前提交已被服务接收,不能证明计算完成;数据库 RUNNING 也不能证明分析器从未对外部系统做过事。
1 | |
重启入口只为单实例提供确定动作
SQL 表增加 failure_reason,已有表由 ADD COLUMN IF NOT EXISTS 补列;Lookup 和 HTTP JSON 对有原因的记录都返回它。显式启动入口 newTaskHTTPServiceWithSQLRecovering 先在一个事务中把遗留 RUNNING 改为 FAILED、计数清零、写入 process exited before worker completion,随后读出 QUEUED 的任务 ID 与原文,关闭 Rows 后提交。事务失败便返回错误,不启动执行器;Commit 返回错误时也不能推断更新必然没发生。
恢复事务提交后,原有有界执行器只收到仍为 QUEUED 的通知。它通过上一章的 Claim 条件更新争取领取资格,而不把内存队列当数据库的最终状态来源。恢复时还扫描合法的 task[n] 编号,下一次新提交从已有最大编号之后分配,避免重启后重新生成 task[0]。测试中第一次恢复报告 failed=1、queued=1、nextID=2;GET task[0] 为 FAILED、带原因且计数为零;等待 worker 退出后,task[1] 为 SUCCEEDED、words=2。第二次恢复没有重复改写终态或重新入队,后续新提交拿到 task[2]。
之所以新增显式恢复构造入口,而不是让任何 SQL 仓库初始化都标记 RUNNING,是因为既有测试与可选 SQL 构造路径可能只是连接到一个仍在工作的实例。同一张表若被另一个运行中的服务误判为遗留任务,就会把活跃计算写成 FAILED。当前恢复入口只供确认旧实例已退出的单实例部署使用;多个实例并行的心跳、租约和抢占尚未实现。
练习:① 子进程死前 task[0] 已调用外部收费 API,但尚未完成 SQL 终态提交。能否恢复为 QUEUED 并自动再执行?答案:不能,否则可能再次收费;本章明确记 FAILED 和原因,保留需要人工核对的事实。② 第二次启动还需扫描历史 ID 吗?需要;进程内 nextID 随进程消失,不扫描会与数据库主键冲突。③ 收到 HTTP 202 就能称数据库事务已经提交、外部动作完成吗?前半句只适用于本次成功写入且服务已发出应答的 SQL 提交流程;外部动作仍未被 202 证明。应答丢失时能否安全重试依旧需要幂等请求 ID,本工程尚无这项能力。
本章的正反场景在真实数据库上单次和 15 次复跑,两包全量测试、本机 race、CLI 正反、进程的信号退出及重启前后 SQL/HTTP 状态均保存命令、双流和退出码于 writing-plans/go-language/evidence/28/。没有 DSN 会 Skip SQL 测试,不能据此声称已验证重启;无 race 报告只限实际执行路径。数据库自身崩溃、提交应答未知、多个实例同时领取、外部副作用去重、生产重启编排、其他平台、全站构建与发布仍 NOT_RUN。下一章将把单元、HTTP 和真实数据库测试的证明范围拆开验收。
参考资料
- PostgreSQL 16 Transactions:本章 HTTP 200 官方原文、版本和退出码保存在
writing-plans/go-language/evidence/28/pg-transactions-doc.*。 - Go 1.27.1
database/sql.DB.BeginTx、sql.Tx.Commit、sql.Rows.Close:冻结工具链的实际go doc原文、双流和退出码见writing-plans/go-language/evidence/28/doc-*。






