原来的 JudgeServer 按核数起 gunicorn worker、每份提交再按核数开进程池,空闲内存跟着核数走
(2 核 52MB、16 核 305MB)。换成 go-judge 后空闲 16MB,同一批提交判题中 80–100MB(原来约 370MB)。
go-judge 只管在沙箱里跑命令,编译、逐点运行、比对输出、定状态码搬到 judge/sandbox.ts,
口径逐条照搬 JudgeServer,出参形状不变。拿生产库真实提交新旧逐点对比:C 2000 份 1989 一致、
C++ 891 份 890 一致、Python 2000 份全一致;不一致的是 system("pause")(现在不再判运行时错误)、
未定义行为、endl 死循环打印(运行时错误变运行超时),见 docker/judge/README.md。
- 判题容器改成 privileged(go-judge 要自己建 cgroup),镜像 oj2-judge-3
- 心跳改由 worker 每 5 秒问判题机 /version 代记,删掉 /api/judge-server/heartbeat
- 前端统一用 stripJudgePath 去掉判题机工作目录(新的 /w/ 和旧的 /judger/run/)
- 提交前编译检查只编译不运行
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
2.5 KiB
Bash
Executable File
69 lines
2.5 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
#
|
||
# 构建判题沙箱镜像(本机构建,产物用 docker save 传到服务器和机房)。
|
||
#
|
||
# docker/judge/build.sh # 构建并打 tag
|
||
# docker/judge/build.sh --save # 顺便导出 tar(给 scp 用)
|
||
# docker/judge/build.sh --no-cache # 不吃构建缓存
|
||
# docker/judge/build.sh --no-mirror # 不走国内镜像源(默认走)
|
||
#
|
||
# 镜像 = go-judge 官方镜像里的那个二进制 + debian 的 gcc / python。构建上下文就是
|
||
# docker/judge/ 这个目录(Dockerfile + mount.yaml)。
|
||
#
|
||
# 上传和切换见 docker/judge/README.md。
|
||
|
||
[ -n "${BASH_VERSION:-}" ] || exec bash "$0" "$@"
|
||
set -euo pipefail
|
||
|
||
cd "$(dirname "${BASH_SOURCE[0]}")/../.."
|
||
|
||
# 我们自己构建的第几版判题镜像(官方 JudgeServer 算第 1 版,自己重编的 JudgeServer
|
||
# 是第 2 版,换成 go-judge 是第 3 版)。
|
||
# **改工具链就把末尾的序号 +1**(下一版叫 oj2-judge-4),别在同一个名字上重建 ——
|
||
# compose 的 `up -d` 不带 --pull,名字没变就会静默用机器上的旧镜像。
|
||
IMAGE=oj2-judge-3
|
||
|
||
SAVE=0
|
||
BUILD_ARGS=()
|
||
for arg in "$@"; do
|
||
case "$arg" in
|
||
--save) SAVE=1 ;;
|
||
--no-cache) BUILD_ARGS+=(--no-cache) ;;
|
||
# 默认用国内镜像源(Dockerfile 顶部的 ARG)。在能直连的网络里用这个关掉,
|
||
# 换回 deb.debian.org。
|
||
--no-mirror)
|
||
BUILD_ARGS+=(
|
||
--build-arg APT_MIRROR=http://deb.debian.org/debian
|
||
--build-arg APT_SECURITY_MIRROR=http://deb.debian.org/debian-security
|
||
) ;;
|
||
*) echo "未知参数:$arg(可用:--save、--no-cache、--no-mirror)" >&2; exit 2 ;;
|
||
esac
|
||
done
|
||
|
||
say() { printf '\n\033[1;36m==> %s\033[0m\n' "$*"; }
|
||
ok() { printf ' \033[32m✓\033[0m %s\n' "$*"; }
|
||
die() { printf '\n\033[1;31m❌ %s\033[0m\n\n' "$*" >&2; exit 1; }
|
||
|
||
command -v docker >/dev/null || die "没装 docker"
|
||
[ -f docker/judge/Dockerfile ] || die "docker/judge/Dockerfile 不见了,当前目录:$PWD"
|
||
|
||
say "构建 $IMAGE"
|
||
docker build "${BUILD_ARGS[@]}" -t "$IMAGE" docker/judge
|
||
ok "$IMAGE"
|
||
|
||
say "镜像里的工具链"
|
||
docker run --rm --entrypoint sh "$IMAGE" -c '
|
||
printf "gcc %s\n" "$(gcc -dumpfullversion)"
|
||
printf "g++ %s\n" "$(g++ -dumpfullversion)"
|
||
printf "python3 %s\n" "$(python3 -V | cut -d" " -f2)"
|
||
printf "go-judge %s\n" "$(go-judge -version | head -1)"
|
||
'
|
||
|
||
if [ "$SAVE" = 1 ]; then
|
||
out="dist/${IMAGE/:/-}.tar"
|
||
mkdir -p dist
|
||
say "导出 $out"
|
||
docker save "$IMAGE" -o "$out"
|
||
ok "$(du -h "$out" | cut -f1) → scp 到服务器后 docker load -i"
|
||
fi
|