Project

Verwandlung Online Judge

Cross-platform online judge for competitive programming contests.

Stars Live verwandlung.org

Introduction

An Online Judge (OJ) is a web-based system used in competitive programming. It presents algorithmic problems, accepts code submissions in various languages, automatically compiles and runs the code against hidden test cases, and immediately tells the user whether their solution is correct, all without any human involvement in the grading process. Platforms like LeetCode and Codeforces are well-known examples.

Verwandlung Online Judge is a self-hostable, open-source OJ built for running your own contests or practice environment. Its main distinguishing feature at the time of release was cross-platform support: most open-source OJs were Linux-only due to their reliance on Linux-specific sandboxing APIs, whereas Verwandlung runs natively on both Windows and Linux.

The name Verwandlung traces back through a chain of references: LinkedIn’s distributed message queue Kafka was named after the author Franz Kafka; Alibaba’s MetaQ was built on top of Kafka and took its name from Kafka’s most famous work, Metamorphosis. Since a message queue is a core component of this project, the name was chosen as Verwandlung, the German title of Metamorphosis.

I shared a more detailed write-up of the design on Zhihu: 如何实现一个在线评测系统(Online Judge)? and Online Judge 系统是怎么判断用户提交的代码是否正确运行的?.

Architecture

The system is split into two independent modules: Web and Judge Worker, connected through an ActiveMQ message queue.

Web handles all user-facing functionality: problem management, submission history, contest administration, and result display. When a user submits code, the web server does not evaluate it directly; instead, the submission is pushed onto the message queue, keeping the web layer responsive and making it easy to scale out judging capacity by running multiple judge workers in parallel.

Judge Worker consumes submissions from the queue, compiles and executes the code, and reports results back. The stack has since been modernized onto Spring Boot (Spring Framework 7, Jakarta EE, JDK 17+): Spring Security handles authentication and authorization, MyBatis over MySQL handles persistence, and ActiveMQ is the message broker. New passwords are stored with BCrypt, while legacy MD5 hashes remain accepted so existing accounts keep working. NoSQL was deliberately omitted to keep deployment simple.

Cross-Platform Support

Cross-platform judging is the core technical challenge of the project. Each judge worker runs untrusted submissions through a thin JNI layer that calls native OS facilities directly, so everything above that OS boundary stays in pure Java and the same codebase compiles and runs on both platforms without modification.

What that native layer does has since been overhauled from simple measurement into proper, layered sandboxing:

  • On Linux, each submission runs as an unprivileged user with its network cut off (a network namespace), its system calls restricted (a seccomp filter), and its resources capped (setrlimit); CPU time and peak memory are read from the kernel via getrusage / wait4.
  • On Windows, each submission runs under a separate low-privilege account inside a Job Object, with CPU time and memory reported by the Windows API (GetProcessTimes, GetProcessMemoryInfo).

Crucially, execution time is now measured as the CPU time the submission itself consumes (user + system), not wall-clock time, so a verdict is no longer skewed by the operating system scheduling other processes; run times are accurate and reproducible.

On Linux, the worker can alternatively delegate to isolate (the sandbox used by the International Olympiad in Informatics), which layers on cgroups v2 resource control and filesystem isolation, recommended for production deployments.

Real-Time Results

Rather than waiting for all test cases to finish before showing a verdict, Verwandlung streams results back one test case at a time using Server-Sent Events (SSE). As the judge worker finishes each test case, it posts a result message back onto the ActiveMQ queue. The web server listens on the same queue and immediately forwards each message to the waiting browser, so users see their results appear progressively.

Screenshots