Algocode
Distributed online judge for C++. Microservices and kernel isolation.
Problem
Running untrusted user code at scale without a shared blast radius between submissions.
Built
3 independently deployable services (Auth, Code Manager, RCE Engine) coordinated through RabbitMQ. Each submission spawns an ephemeral sibling Docker container with Linux namespaces, cgroups, and seccomp enforcing strict CPU/memory/time limits.
3
independent services
AC/WA/TLE/MLE/SegFault
verdicts
kernel-level
isolation
token-bucket
rate limiting
The build
[Idea]
Algocode was the project where I had to think about what 'securely running untrusted code' actually means. The naive version is a Docker container per submission, and it sounds fine until you realize that 'shared blast radius' is the entire problem. One user submits a fork bomb, the whole node dies.
[Framing]
The fix was Linux isolation primitives. Namespaces for filesystem and process isolation. cgroups for CPU and memory caps. seccomp to whitelist the syscalls a C++ judge actually needs, since the syscall surface for a C++ binary is small and predictable. Each submission gets a sibling container that lives only as long as the submission, with hard wall-clock limits and a hard syscall allowlist.
[Build]
The system splits into three independently deployable services. Auth handles user management and tokens. Code Manager is the public-facing API. It validates the user, writes the submission to its own database, and publishes an event to RabbitMQ tagged by language. RCE Engine consumes from its language-specific queue and runs the judge in the hard-isolated sibling container. Results publish back via a unified RabbitMQ result queue, and Code Manager caches in Redis and persists to Mongo.
[Deploy]
The whole thing runs on free-tier AWS EC2 plus an Azure VM (1GB RAM each), which is why the rate-limit middleware exists. Three submissions per minute per user, via Token Bucket. I built the limiter in Django Middleware rather than reaching for an API gateway, because adding cloud spend for one feature felt wrong. The split into three repos (algocode-auth, code-manager, rcee) was deliberate. Independent deploys and independent failures.
[What's next]
What's next, if I pick this back up. Skip Mongo for results and use Postgres JSONB, one less service to operate. Build a frontend. Add Java and Python judges (the RCE Engine stubs are in place). The rate-limit logic deserves a small dashboard so I can see who's hitting it.
Stack
9 techs · grouped by layerBackend
- Django
- DRF
- RabbitMQ
- JWT/OAuth2
Infrastructure
- Docker
- AWS
Data layer
- PostgreSQL
- MongoDB
- Redis
Also used
Links
Related writing
8 posts reference Algocode- PostgreSQL Part 1: Install, Setup, Creating Tables and CRUD Operations
medium · 7 min read · postgresql · database · sql · crud
- SQL Joins in PostgreSQL: Query Across Multiple Tables and Actually Understand What You Are Asking
medium · 8 min read · postgresql · sql · joins
- Aggregations & Grouping in SQL: The Queries Behind Every Dashboard and Report
medium · 8 min read · postgresql · sql · aggregations
- Your Easy Guide to Design Highly Available Systems With Redis. Part 1
medium · 8 min read · redis · high-availability · cache · distributed
- My Experience Building a LeetCode-like Online Judge (and How You Can)
medium · 8 min read · microservices · docker · rabbitmq · distributed-systems
- Message Queue 101: Your Ultimate Guide to Understanding Message Queues
medium · 6 min read · rabbitmq · distributed-systems · async
- Message Queue 101: Your Ultimate Guide to Understanding Message Queues
native · 7 min read · rabbitmq · distributed-systems · async
- How I Built Algocode. A Distributed Online Judge, Microservices to Kernel Isolation
native · 12 min read · microservices · docker · rabbitmq · distributed-systems