From e921506f403535778e3df03eeca4c05e46e1af4f Mon Sep 17 00:00:00 2001 From: yuetsh <517252939@qq.com> Date: Thu, 27 Aug 2026 10:51:00 -0600 Subject: [PATCH] =?UTF-8?q?fix(=E6=B5=81=E7=A8=8B=E5=9B=BE):=20=E3=80=8C?= =?UTF-8?q?=E9=87=8D=E6=96=B0=E5=88=A4=E9=A2=98=E3=80=8D=E4=BB=8E=E6=9D=A5?= =?UTF-8?q?=E6=B2=A1=E6=88=90=E5=8A=9F=E8=BF=87=EF=BC=8C=E8=80=8C=E4=B8=94?= =?UTF-8?q?=E4=BC=9A=E6=8A=8A=E5=8E=9F=E6=9D=A5=E7=9A=84=E8=AF=84=E5=88=86?= =?UTF-8?q?=E6=B8=85=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `bullmq` 对自定义 jobId 有一条兼容老式可重复任务的校验:一旦包含 `:`,就必须 正好切成三段(`job.js` 里的 `split(':').length !== 3`),否则抛 `Custom Id cannot contain :`。 - 代码提交的重判用的是 `${id}:rejudge:${时间戳}` —— 三段,能过; - 流程图的重判用的是 `${id}:${时间戳}` —— **两段,必抛**。 所以这个接口从上线起就没有成功过一次。更糟的是清空评分发生在入队**之前**: await db.update(...).set({ status: 0, aiScore: null, ... }) await flowchartQueue.add(...) // ← 在这里抛,500 每点一次「重新判题」,原来的分数、等级、反馈、评分明细就永久丢一次,提交卡在 PENDING,队列里没有任何任务会来救它,老师看到的只是「重新评分失败」。 改成三段式 jobId,并把入队失败落成 FAILED(而不是留在 PENDING)—— 与 `POST /flowcharts` 的处理保持一致。 之前几轮验证没发现,是因为当时手上只有一条 PENDING 的提交,被 409(状态不允许 重判)挡在了入队之前,正好绕开了这个 bug。这次完整走教师流程才撞上。 实测:修复前点重判 → 前端「重新评分失败」、库里 status 变 0 且分数清空、 api 日志抛 `Custom Id cannot contain :`;修复后 → 「重新评分已提交」, 70分B级 重评为 86分A级。 Co-Authored-By: Claude Opus 5 --- apps/api/src/routes/flowchart.ts | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/apps/api/src/routes/flowchart.ts b/apps/api/src/routes/flowchart.ts index c1a7bad..b23e75a 100644 --- a/apps/api/src/routes/flowchart.ts +++ b/apps/api/src/routes/flowchart.ts @@ -330,7 +330,22 @@ flowchartRoutes.post("/flowcharts/:id/retry", requireAuth, async (c) => { status: 0, aiScore: null, aiGrade: null, aiFeedback: null, aiSuggestions: null, aiCriteriaDetails: {}, processingTime: null, evaluationTime: null, }).where(eq(schema.flowchartSubmission.id, row.flowchart.id)) - await flowchartQueue.add("evaluate", { submissionId: row.flowchart.id }, { jobId: `${row.flowchart.id}:${Date.now()}` }) + try { + // jobId 必须**正好三段**:bullmq 对含 `:` 的自定义 id 有一条兼容老的可重复 + // 任务的校验(job.js 的 `split(':').length !== 3`),两段会直接抛 + // `Custom Id cannot contain :`。原来写的是 `${id}:${时间戳}`,于是这个接口 + // 从来没成功过 —— 而清空评分在入队之前,每点一次就把原来的分数永久清掉、 + // 提交卡在 PENDING 且没有任何任务会来救它。 + await flowchartQueue.add( + "evaluate", + { submissionId: row.flowchart.id }, + { jobId: `${row.flowchart.id}:retry:${Date.now()}` }, + ) + } catch (error) { + // 入队失败就落 FAILED,别把提交丢在 PENDING 上 —— 和 POST /flowcharts 同一处理 + await db.update(schema.flowchartSubmission).set({ status: 3 }).where(eq(schema.flowchartSubmission.id, row.flowchart.id)) + return failure(c, 502, "queue-unavailable", "Evaluation queue is unavailable") + } return success(c, createFlowchartResponseSchema.parse({ submissionId: row.flowchart.id, status: "pending" })) })