修复任务恢复尝试范围并更新进度
This commit is contained in:
parent
df88d00825
commit
9c3f2a6939
@ -361,6 +361,16 @@ func (r *SQLTaskRepository) RecoverInterruptedTasks(ctx context.Context, finishe
|
||||
rollback()
|
||||
return 0, fmt.Errorf("\u8bfb\u53d6\u4e2d\u65ad\u4efb\u52a1\u5ba1\u8ba1\u6570\u91cf\u5931\u8d25\uff1a%w", err)
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, r.query(`UPDATE task_attempts
|
||||
SET status = 'failed', message = ?, finished_at = ?
|
||||
WHERE status IN ('queued', 'running', 'retry_wait', 'cancelling')
|
||||
AND task_id IN (
|
||||
SELECT id FROM tasks
|
||||
WHERE status IN ('queued', 'running', 'retry_wait', 'cancelling')
|
||||
)`), recoveryMessage, finishedAt); err != nil {
|
||||
rollback()
|
||||
return 0, fmt.Errorf("恢复中断任务尝试失败:%w", err)
|
||||
}
|
||||
result, err := tx.ExecContext(ctx, r.query(`UPDATE tasks
|
||||
SET status = 'failed', stage = 'service_restart', message = ?, finished_at = ?, updated_at = ?
|
||||
WHERE status IN ('queued', 'running', 'retry_wait', 'cancelling')`), recoveryMessage, finishedAt, finishedAt)
|
||||
@ -377,16 +387,6 @@ func (r *SQLTaskRepository) RecoverInterruptedTasks(ctx context.Context, finishe
|
||||
rollback()
|
||||
return 0, fmt.Errorf("\u4e2d\u65ad\u4efb\u52a1\u5ba1\u8ba1\u6570\u91cf\u4e0e\u4efb\u52a1\u6570\u91cf\u4e0d\u4e00\u81f4\uff1a\u5ba1\u8ba1 %d,\u4efb\u52a1 %d", auditCount, count)
|
||||
}
|
||||
if _, err := tx.ExecContext(ctx, r.query(`UPDATE task_attempts
|
||||
SET status = 'failed', message = ?, finished_at = ?
|
||||
WHERE status IN ('queued', 'running', 'retry_wait', 'cancelling')
|
||||
AND task_id IN (
|
||||
SELECT id FROM tasks
|
||||
WHERE status = 'failed' AND stage = 'service_restart' AND finished_at = ?
|
||||
)`), recoveryMessage, finishedAt, finishedAt); err != nil {
|
||||
rollback()
|
||||
return 0, fmt.Errorf("\u6062\u590d\u4e2d\u65ad\u4efb\u52a1\u5c1d\u8bd5\u5931\u8d25\uff1a%w", err)
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return 0, fmt.Errorf("\u63d0\u4ea4\u4e2d\u65ad\u4efb\u52a1\u6062\u590d\u4e8b\u52a1\u5931\u8d25\uff1a%w", err)
|
||||
}
|
||||
|
||||
@ -361,6 +361,42 @@ func TestSQLTaskRepositoryRecoversInterruptedTasksAndAttempts(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSQLTaskRepositoryRecoveryDoesNotTouchHistoricalRestartTaskAttempts(t *testing.T) {
|
||||
repository, db := newTaskRepositoryTest(t)
|
||||
defer db.Close()
|
||||
ctx := context.Background()
|
||||
finished := time.Date(2026, 8, 30, 10, 0, 0, 0, time.UTC)
|
||||
|
||||
for _, item := range []Task{
|
||||
{ID: "task-active-recovery", DomainID: "domain-1", TaskType: "certificate_issue", Status: "running", Stage: "certificate_issue"},
|
||||
{ID: "task-historical-restart", DomainID: "domain-2", TaskType: "certificate_deploy", Status: "failed", Stage: "service_restart", Message: "历史恢复失败", FinishedAt: &finished},
|
||||
} {
|
||||
if err := repository.CreateTask(ctx, item); err != nil {
|
||||
t.Fatalf("创建恢复边界任务失败:%v", err)
|
||||
}
|
||||
}
|
||||
for _, attempt := range []TaskAttempt{
|
||||
{ID: "attempt-active-recovery", TaskID: "task-active-recovery", AttemptNumber: 1, Stage: "certificate_issue", Status: "running"},
|
||||
{ID: "attempt-historical-restart", TaskID: "task-historical-restart", AttemptNumber: 1, Stage: "certificate_deploy", Status: "running"},
|
||||
} {
|
||||
if err := repository.CreateAttempt(ctx, attempt); err != nil {
|
||||
t.Fatalf("创建恢复边界任务尝试失败:%v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if count, err := repository.RecoverInterruptedTasks(ctx, finished); err != nil || count != 1 {
|
||||
t.Fatalf("恢复中断任务数量错误:%d %v", count, err)
|
||||
}
|
||||
recovered, err := repository.ListAttempts(ctx, "task-active-recovery")
|
||||
if err != nil || len(recovered) != 1 || recovered[0].Status != "failed" {
|
||||
t.Fatalf("活动任务尝试未被恢复:%+v %v", recovered, err)
|
||||
}
|
||||
historical, err := repository.ListAttempts(ctx, "task-historical-restart")
|
||||
if err != nil || len(historical) != 1 || historical[0].Status != "running" || historical[0].FinishedAt != nil {
|
||||
t.Fatalf("历史恢复任务尝试被错误修改:%+v %v", historical, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSQLTaskRepositoryRecoveryAuditFailureRollsBack(t *testing.T) {
|
||||
repository, db := newTaskRepositoryTest(t)
|
||||
defer db.Close()
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# Scert 开发任务清单
|
||||
|
||||
## 最新开发进度(2026-09-30,P0-10 崩溃恢复边界修复)
|
||||
|
||||
**总体验收位置继续保持 P0-03:完成,待复审。** 本轮修复服务重启恢复任务尝试的筛选边界,并完成后端本地全量验证;不把本地测试结果写成生产验收结论。
|
||||
|
||||
- [x] P0-10-09:恢复任务尝试仅绑定本次恢复前处于活动状态的任务,避免历史 `service_restart` 记录误命中。
|
||||
- [x] P0-10-09:新增历史任务时间碰撞回归测试,覆盖历史任务及活动任务尝试的差异化结果。
|
||||
- [x] 本轮验证:`go test ./...`、`go vet ./...`、`git diff --check` 全部通过。
|
||||
- [~] P0-10 的 DNS 验证任务、重试幂等、三数据库实机矩阵和统一复审仍在进行。
|
||||
- [ ] 远端生产部署、清库初始化、密码 SSH、浏览器缓存清理后的生产流程、HTTPS/DNS/ACME 和最终生产门禁未完成。
|
||||
- [!] 当前不得升级总体验收,仍为 **P0-03:完成,待复审**,没有新增 `[✓]`。
|
||||
|
||||
## 最新开发进度(2026-09-30,P0-10 批量部署结果持久化)
|
||||
|
||||
**总体验收位置继续保持 P0-03:完成,待复审。** 本轮已完成代码开发并通过本地自动化回归,未将本地结果写成生产验收结论。
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# Scert 整改任务执行清单
|
||||
|
||||
## 最新执行记录(2026-09-30,P0-10 崩溃恢复边界修复)
|
||||
|
||||
总体验收继续保持 **P0-03:完成,待复审**。本批登记任务恢复边界修复和本地自动化证据,不替代真实服务器、真实数据库和生产部署验收。
|
||||
|
||||
- [x] 仓储层:恢复任务尝试时先按恢复前活动任务范围更新,再收敛父任务状态。
|
||||
- [x] 回归覆盖:历史 `service_restart` 任务与本次活动任务使用相同完成时间时,历史任务尝试保持原状态。
|
||||
- [x] 自动化门禁:后端全量测试、静态检查、差异检查均通过。
|
||||
- [~] 继续执行:P0-10 的 DNS 验证、重试幂等、跨数据库实机矩阵和统一复审。
|
||||
- [ ] 尚未执行:P0-12、真实三数据库生产数据清理、密码 SSH、远端多服务器部署、HTTPS/DNS/ACME 和最终生产门禁。
|
||||
- [!] 状态约束:不标记 `[✓]`,总体验收仍为 **P0-03:完成,待复审**。
|
||||
|
||||
## 最新执行记录(2026-09-30,P0-10 部署结果查询闭环)
|
||||
|
||||
总体验收继续保持 **P0-03:完成,待复审**。本批只登记代码开发和本地回归证据,不替代真实服务器、真实数据库和生产部署验收。
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# Scert 整改、合并与优化清单
|
||||
|
||||
## 最新进度摘要(2026-09-30,P0-10 崩溃恢复边界修复)
|
||||
|
||||
**总体验收位置仍为 P0-03:完成,待复审。** 本轮继续先开发、后统一测试,修复服务重启恢复任务尝试的历史记录误命中风险;本地验证结果不等同于生产部署验收通过。
|
||||
|
||||
- [x] 已完成,等待复审:恢复任务尝试改为依据恢复前仍处于活动状态的父任务筛选,不再依赖恢复完成时间反查。
|
||||
- [x] 已完成,等待复审:新增历史 `service_restart` 任务时间碰撞回归测试,确认历史活动尝试不会被本次恢复错误修改。
|
||||
- [x] 本轮验证:后端 `go test ./...`、`go vet ./...`、`git diff --check` 均通过。
|
||||
- [~] P0-10 的 DNS 验证任务、重试幂等、跨数据库实机矩阵和统一复审仍需继续。
|
||||
- [ ] 真实生产数据库清理、密码 SSH、远端多服务器部署、HTTPS/DNS/ACME、平台服务和最终生产门禁仍未完成。
|
||||
- [!] 不新增 `[✓]` 复审通过项;总体验收继续保持 **P0-03:完成,待复审**。
|
||||
|
||||
## 最新进度摘要(2026-09-30,P0-10 批量部署结果持久化)
|
||||
|
||||
**总体验收位置仍为 P0-03:完成,待复审。** 本轮完成批量部署结果的持久化、项目范围查询和 HTTP 读取接口,并完成本地自动化验证;这些结果不等同于生产部署验收通过。
|
||||
|
||||
@ -1,5 +1,16 @@
|
||||
# 基础整改任务规格
|
||||
|
||||
## 最新规格执行进度(2026-09-30,P0-10 崩溃恢复边界修复)
|
||||
|
||||
**总体验收位置仍为 P0-03:完成,待复审。** 本轮补齐服务重启恢复中任务尝试的范围约束,并通过本地全量验证,尚未满足生产验收的实机条件。
|
||||
|
||||
- [x] 规格实现:恢复任务尝试依据恢复前活动状态的父任务筛选,不使用完成时间和阶段反查历史任务。
|
||||
- [x] 规格验证:新增历史恢复任务时间碰撞测试,确认历史任务尝试不被错误收敛。
|
||||
- [x] 规格验证:`go test ./...`、`go vet ./...`、`git diff --check` 通过。
|
||||
- [~] 规格待续:DNS 验证、重试幂等、真实三数据库和统一复审。
|
||||
- [ ] 规格未验收:远端密码 SSH、多服务器生产推送、HTTPS/DNS/ACME、平台服务和最终生产门禁。
|
||||
- [!] 不得把本轮局部开发标记为 `[✓]`;总体验收继续为 **P0-03:完成,待复审**。
|
||||
|
||||
## 最新规格执行进度(2026-09-30,P0-10 部署结果持久化)
|
||||
|
||||
**总体验收位置仍为 P0-03:完成,待复审。** 本轮将批量部署结果的存储、查询、权限和错误脱敏纳入已完成开发范围,但尚未满足生产验收的实机条件。
|
||||
|
||||
Loading…
Reference in New Issue
Block a user