Some checks failed
Deploy / deploy (push) Has been cancelled
原来只有 `apps/web` 在 Prettier 下(配置在 `apps/web/.prettierrc.toml`、脚本在 web 的 package.json),后端和契约从来没格式化过 —— 手写在 100 列上下,`db/schema.ts` 还是 drizzle-kit pull 留下的 tab 缩进。两套口径分叉久了,跨端改一处就得记着「这边 什么风格」。 - 配置搬到根目录 `.prettierrc.toml`,内容不变(`semi=false`,其余全默认, printWidth 80 —— 和前端已有的格式一致,不另立一套宽度); - 脚本统一成根目录 `bun run fmt`,覆盖 `apps/*/src`、`apps/web/tests` 和两个构建 配置;web 自己那份 `fmt` 和重复的 prettier 依赖删掉; - `.prettierignore` 挡掉两类不该碰的:drizzle-kit 生成的 `src/db/meta/` 结构快照 (它是 db:generate 的比对输入,只该由 drizzle-kit 写)、unplugin 每次 dev 都会 重写的 `auto-imports.d.ts` / `components.d.ts`; - 全量跑了一遍。纯格式,无行为改动:api typecheck / check:routes / check:ast、 前端 type-check 全过,起 api 打了接口确认正常。前端这 39 个文件的小改动是 prettier 版本漂移(类型断言的换行口径变了),不是新配置带来的。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
69 lines
2.2 KiB
TypeScript
69 lines
2.2 KiB
TypeScript
import { Worker } from "bullmq"
|
||
|
||
import { config } from "./config"
|
||
import { judgeQueueName, type JudgeJobData } from "./judge/job"
|
||
import { failAbandonedSubmission, judgeSubmission } from "./judge/run"
|
||
import { flowchartQueueName, type FlowchartJobData } from "./flowchart/job"
|
||
import { evaluateFlowchart } from "./flowchart/run"
|
||
import { createBlockingRedis } from "./redis"
|
||
|
||
const worker = new Worker<JudgeJobData>(
|
||
judgeQueueName,
|
||
async (job) => judgeSubmission(job.data),
|
||
{
|
||
connection: createBlockingRedis(),
|
||
concurrency: config.judgeConcurrency,
|
||
},
|
||
)
|
||
|
||
const flowchartWorker = new Worker<FlowchartJobData>(
|
||
flowchartQueueName,
|
||
// attemptsMade 是「此前已经失败过几次」,当前这次还没计进去,
|
||
// 所以最后一次尝试的判据是 attemptsMade + 1 >= attempts
|
||
async (job) =>
|
||
evaluateFlowchart(job.data, {
|
||
isFinalAttempt: job.attemptsMade + 1 >= (job.opts.attempts ?? 1),
|
||
}),
|
||
{ connection: createBlockingRedis(), concurrency: 2 },
|
||
)
|
||
|
||
worker.on("ready", () => {
|
||
console.log(`Judge worker ready (concurrency=${config.judgeConcurrency})`)
|
||
})
|
||
worker.on("failed", async (job, error) => {
|
||
console.error(`Judge job ${job?.id ?? "unknown"} failed`, error)
|
||
// 队列没配 attempts,失败即终局;worker 被杀掉那种 BullMQ 走完 stalled 重试也会
|
||
// 落到这里。不在这里写一个终态,提交就永远停在「等待评分」,没有任何人会再管它。
|
||
const submissionId = job?.data.submissionId
|
||
if (!submissionId) return
|
||
try {
|
||
await failAbandonedSubmission(submissionId, error)
|
||
} catch (markError) {
|
||
console.error(
|
||
`Failed to mark submission ${submissionId} as system error`,
|
||
markError,
|
||
)
|
||
}
|
||
})
|
||
worker.on("error", (error) => {
|
||
console.error("Judge worker error", error)
|
||
})
|
||
flowchartWorker.on("ready", () =>
|
||
console.log("Flowchart worker ready (concurrency=2)"),
|
||
)
|
||
flowchartWorker.on("failed", (job, error) =>
|
||
console.error(`Flowchart job ${job?.id ?? "unknown"} failed`, error),
|
||
)
|
||
flowchartWorker.on("error", (error) =>
|
||
console.error("Flowchart worker error", error),
|
||
)
|
||
|
||
async function shutdown() {
|
||
await worker.close()
|
||
await flowchartWorker.close()
|
||
process.exit(0)
|
||
}
|
||
|
||
process.on("SIGINT", shutdown)
|
||
process.on("SIGTERM", shutdown)
|