fix(gateway): 任务落库失败不再吞 —— 关键写失败上浮 5xx (P0-2)
DEPTH_ROADMAP:225 未完项 + 完成度审计 P0-2:launch() 里 SaveTask 是 best-effort, DB 写失败只 log 却照样 PublishTask + 返 202。结果任务发出去在后端跑了,却不进 运行历史、复盘不了、报告类的用户切页面回来彻底找不回——用户以为成功、实际没落库。 - SaveTask 对「DB 降级(nil)」返 nil、对「DB 活着写失败」返真 error,天然可区分: 前者静默跳过(开发态本就无库),后者上浮为提交失败。落库在 Publish 之前, 失败时还没发布,中止干净、不产生"看不见的执行"。 - 两个调用点(SubmitTask/GenerateReport)已把 launch 错误映射 5xx,无需再改。 范围克制:审计列的其它 best-effort 点保持不动——dispatcher 的异步回写 (UpdateTaskStatus/SaveTaskOutput/SaveTaskTrace)、审计日志、用量累计计数, 都不是"用户等着响应"的路径,没有请求可返 5xx,best-effort 是对的。 唯独 launch 这处是"用户以为提交成功实际没有",才该阻断。 live 验证:改名 task 表模拟 DB 写失败 → 提交返 502+明确文案(不再假 202); 表改回 → 立刻恢复 202。happy path 202+落库不变。go build/vet/test 全绿。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ package handler
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -71,9 +72,14 @@ func (h *Handler) preflight(c *gin.Context) (string, bool) {
|
||||
// 报告生成此前只 PublishTask,这两样都没有,所以报告既进不了运行历史,
|
||||
// 切个页面回来也彻底找不回——它明明在后端好好地跑完了。
|
||||
func (h *Handler) launch(c *gin.Context, task *contract.Task) error {
|
||||
// 持久化任务提交(best-effort:降级模式下静默跳过,不阻断发布)。
|
||||
// 持久化任务提交。DB 降级(nil)时 SaveTask 返 nil 静默跳过(开发态本就无库,不阻断);
|
||||
// 但 DB 活着却写失败 → 真故障,绝不能吞:一旦 PublishTask 发出去,任务就在后端跑了,
|
||||
// 却不进运行历史、复盘不了、报告类的会彻底"丢"(用户切页面回来找不回)。
|
||||
// 宁可这里失败上浮 5xx 让用户重试,也不发一个"看不见的执行"。落库在 Publish 之前,
|
||||
// 失败时还没发布,中止是干净的。
|
||||
if err := h.db.SaveTask(c.Request.Context(), userID(c), task.ID, string(task.Graph)); err != nil {
|
||||
log.Printf("[gateway] save task %s failed: %v", task.ID, err)
|
||||
return fmt.Errorf("任务落库失败,请重试: %w", err)
|
||||
}
|
||||
if err := h.bus.PublishTask(c.Request.Context(), task); err != nil {
|
||||
return err
|
||||
|
||||
Reference in New Issue
Block a user