fix(queue): 重新调度终态 River 任务

等待异步准入的任务只跳过仍处于活跃状态的 River Job;missing 或 terminal Job 交由准入调度器重新创建,避免非空 river_job_id 永久阻断旧任务。\n\n通用 River 恢复排除等待准入任务,消除双恢复循环与误导日志;事务回滚继续使用独立有界上下文。\n\n验证:真实 PostgreSQL 下异步 Worker 准入验收和跨 Store 队列集成测试均通过。
This commit is contained in:
2026-07-30 17:42:33 +08:00
parent e8893e2b8f
commit fa818e9ebf
5 changed files with 52 additions and 14 deletions
@@ -447,6 +447,29 @@ WHERE id = $1::uuid`, queuedAtomicTask.ID).Scan(&riverJobID, &queuedLeases); err
if riverJobID != queuedSyntheticRiverJobID || queuedLeases != 0 {
t.Fatalf("queued River marker=%d leases=%d, want %d/0", riverJobID, queuedLeases, queuedSyntheticRiverJobID)
}
waitingAsyncTaskIDs, err := first.ListWaitingAsyncAdmissionTaskIDs(ctx, 1000)
if err != nil {
t.Fatalf("list waiting async tasks with missing River job: %v", err)
}
waitingAsyncFound := false
for _, taskID := range waitingAsyncTaskIDs {
if taskID == queuedAtomicTask.ID {
waitingAsyncFound = true
break
}
}
if !waitingAsyncFound {
t.Fatal("waiting async task with missing River job was not dispatchable")
}
recoverableTasks, err := first.ListRecoverableAsyncTasks(ctx, 1000)
if err != nil {
t.Fatalf("list recoverable tasks while admission is waiting: %v", err)
}
for _, item := range recoverableTasks {
if item.ID == queuedAtomicTask.ID {
t.Fatal("generic River recovery claimed a task owned by the async admission dispatcher")
}
}
result, err = second.TryTaskAdmission(ctx, inputFor(queuedAtomicTask, 100, ""))
if err != nil || !result.Admitted || len(result.Leases) != 1 {
t.Fatalf("worker-time queued admission result=%+v err=%v", result, err)