Skip to content

Judge Service

Compile, sandbox, grade. Where user code actually runs.

Python process. RabbitMQ in, HTTP out, nsjail in the middle. User code never runs on the host OS.

Architecture context: Core components.

Queue msg → GET submission + tests → compile in nsjail → run cases → PATCH verdict → delete temp dirs
{ "type": "submission", "id": "uuid" }

Custom input: "type": "input_submission".

From the data layer (judge JWT):

  • Submission body: source, language_id, problem_id
  • Tests: GET /v1/problem_description/{problem_id}/tests
/program_files/{uuid}/
build/ ← source + build.sh from languages.toml
executable/ ← must end up with a runnable main

Failure here → COMPILE_TIME_ERROR, stderr saved, no tests run. Fix your #include, not your algorithm.

stdin = test input. Compare stdout to expected (line-by-line, trimmed whitespace). Stop at first failure. That’s ICPC-style, not “show me all wrong cases.”

Timeouts → TIME_LIMIT_EXCEEDED. OOM → MEMORY_LIMIT_EXCEEDED. Segfault → RUNTIME_ERROR.

{
"status": "ACCEPTED",
"time_elapsed": 0.123,
"failed_test_case_id": null,
"test_case_results": [{ "test_case_id": "...", "passed": true, "stdout": "...", "stderr": "" }]
}

Per-problem limits from the API can override run-time bounds.

LimitCompileRun
CPU time30s10s default
Virtual memory16 MB6 MB default
CPU cores21
File descriptors5123

Also: chroot, UID 99999, no network, seccomp, read-only FS except build/output dirs.

Reality check: this stops casual mischief and runaway loops. A motivated attacker with a sandbox escape is why you isolate the judge network.

More containers = more parallel submissions. RabbitMQ distributes. One worker = one active submission.

Contest rule of thumb: if queue depth climbs through the first hour, add workers before bumping time limits. Users hate TLE inflation more than they hate waiting 30s in queue.

EnvPurpose
RABBITMQ_*Queue
NEXTJUDGE_HOST, NEXTJUDGE_PORTAPI
JUDGE_PASSWORDJudge login (auth)

Startup: fetch languages from API, match names to languages.toml, build ID map. Name mismatch = silent failure at submit time. Keep them in sync.

  • Redelivered poison message: rejected after one retry (no infinite loop)
  • API down during PATCH: submission may stay PENDING until retry logic runs; check logs
  • Compile works locally, fails on judge: different compiler version or missing {IN_FILE} in build script

Logs → stdout → docker logs. Grep for submission_id when debugging a specific stuck submit.

  1. Toolchain in Dockerfile.newbase
  2. [[language]] in languages.toml/executable/main
  3. Rebuild image
  4. POST /v1/languages
  5. Submit reference AC solution

Quirks per language: Supported languages.