Files
OJ2/apps/api/src/main.ts
yuetsh f6bc42f534 docs: 给 OJ2 补一份自己的 CLAUDE.md;Dockerfile 拷上 bunfig.toml
## bunfig.toml 没拷进容器,才是那批「本地能过、容器过不了」的根因

bunfig.toml 里设了 `linker = "hoisted"`,但 Dockerfile 只拷了 package.json 和
bun.lock,于是容器里用的是默认的 isolated 布局(包都在 node_modules/.bun/ 下),
本地靠"提升"才解析得到的包在容器里一律 Could not resolve —— 而本地构建始终是好的,
只有镜像构建才炸。之前是一个一个补直接依赖补过去的(那是对的、该保留),
这里让两边布局一致,是第二道保险。

带上之后装 622 个包(isolated 是 1238),镜像重建通过,二进制在容器里
serve + healthcheck 正常。

顺手补了 main.ts 帮助文本里漏掉的 healthcheck 子命令(compose 里把 command
写错时,看到的就是这行)。

## OJ2/CLAUDE.md

OJ2 是独立仓库,之前没有自己的项目指引。写了一份,重点是几条「不知道就会踩」的:

- **本机 Docker 可用**,整套依赖和上线演练都能在本机跑 —— 别沿用上一代
  "本机跑不起来后端"的旧假设
- 单二进制不能依赖 node_modules,`.node` 资源导入 dev 和编译两种形态行为不同,
  **改完两种形态都要跑**
- SQL 判题 spawn 的是二进制自己,入口必须有 argv 分发,那道递归闸不能删
- 判题状态码三处同步、raw_password 要保留、比赛只有 ACM、前端要兼容老 Chrome
- 不写迁移:新旧后端跑同一套表结构,这是回滚能成立的前提

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 03:37:45 -06:00

53 lines
2.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 唯一入口。所有角色都从这里按子命令分叉。
*
* 为什么不保留三个独立入口文件:`bun build --compile` 一次只产出一个二进制,
* 而部署要跑 HTTP 服务、判题 workerSQL 判题还要 fork 一个能被 SIGKILL 的子进程
* (见 judge/sql/index.ts。三个入口就得编三个二进制、镜像里塞三份运行时。
* 一个二进制 + 子命令镜像里只有一份compose 里改 command 就能换角色。
*
* oj2-api # 等同 serve
* oj2-api serve # HTTP + WebSocket
* oj2-api worker # BullMQ 判题消费者
* oj2-api healthcheck # 探活,给 Dockerfile 的 HEALTHCHECK 用
* oj2-api sql-child # SQL 判题子进程,由服务自己 spawn不该手动调
*
* 用动态 import 而非顶层 import这几个模块都有导入即执行的副作用
* Bun.serve、连 Redis 开消费者),静态导入会让 sql-child 也把整个服务拉起来。
*/
export {} // 只有动态 import 的话 TS 不认这是模块,顶层 await 会报错
const command = process.argv[2] ?? "serve"
switch (command) {
case "serve":
await import("./index")
break
case "worker":
await import("./worker")
break
case "sql-child": {
const { runSqlChild } = await import("./judge/sql/child")
await runSqlChild()
break
}
// 运行镜像是 debian-slim没有 curl/wget探活让二进制自己做。
// 只打 /health不碰库 —— 库挂了该由库自己的 healthcheck 报,
// 不该让 api 容器跟着被判成不健康、进而被重启。
case "healthcheck": {
const { config } = await import("./config")
try {
const response = await fetch(`http://127.0.0.1:${config.port}/health`, {
signal: AbortSignal.timeout(3000),
})
process.exit(response.ok ? 0 : 1)
} catch {
process.exit(1)
}
}
default:
console.error(`未知子命令:${command}\n可用serve | worker | healthcheck | sql-child`)
process.exit(2)
}