fix(题单): 奖章补发改成二进制子命令,独立脚本在生产跑不了
Some checks failed
Deploy / deploy (push) Has been cancelled

上一版把补发写成 `bun src/scripts/backfill-problemset-badges.ts`,那在生产上根本执行
不了 —— api 镜像是 debian-slim + 一个编译好的 oj2-api,既没有 bun 也没有源码。

改成 main.ts 的子命令,跑法对齐 migrate(deploy.sh:197 就是这个形态):

  docker compose -f docker/compose.debian.yml run --rm oj-api oj2-api backfill-badges
  docker compose -f docker/compose.debian.yml run --rm oj-api oj2-api backfill-badges --apply

脚本本身从「导入即执行」改成导出一个返回退出码的函数,main.ts 负责解析参数和 exit。
package.json 的 backfill:badges 也指向同一入口,本机和生产走的是同一条代码路径。

用编译出来的二进制在 /tmp 下实跑过全部四条路径(预演 / --apply 后自动复核 / 重复跑
幂等 / 误发时拒绝执行并退 1,加 --allow-revoke 才收回),确认动态 import 的模块进了
bundle、不依赖源码树。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QqqZwxtXLo2GTqMi51C94D
This commit is contained in:
2026-08-31 08:26:27 -06:00
parent f9354b0df1
commit 05cf8011e3
3 changed files with 91 additions and 74 deletions

View File

@@ -12,6 +12,7 @@
* oj2-api healthcheck # 探活,给 Dockerfile 的 HEALTHCHECK 用
* oj2-api sql-child # SQL 判题子进程,由服务自己 spawn不该手动调
* oj2-api migrate # 执行待办的数据库迁移,部署时由 docker/deploy.sh 调
* oj2-api backfill-badges # 补发历史欠账的题单奖章,默认只读预演,--apply 才落库
*
* 用动态 import 而非顶层 import这几个模块都有导入即执行的副作用
* Bun.serve、连 Redis 开消费者),静态导入会让 sql-child 也把整个服务拉起来。
@@ -33,6 +34,15 @@ switch (command) {
await runMigrations()
break
}
// 一次性的数据订正,跟着二进制走而不是留成源码脚本 —— 生产镜像里没有 bun 也没有源码
case "backfill-badges": {
const { backfillProblemSetBadges } = await import("./scripts/backfill-problemset-badges")
const args = process.argv.slice(3)
process.exit(await backfillProblemSetBadges({
apply: args.includes("--apply"),
allowRevoke: args.includes("--allow-revoke"),
}))
}
case "sql-child": {
const { runSqlChild } = await import("./judge/sql/child")
await runSqlChild()
@@ -53,6 +63,6 @@ switch (command) {
}
}
default:
console.error(`未知子命令:${command}\n可用serve | worker | migrate | healthcheck | sql-child`)
console.error(`未知子命令:${command}\n可用serve | worker | migrate | backfill-badges | healthcheck | sql-child`)
process.exit(2)
}