Infrastructure primitives
Code execution sandbox - running a stranger's program
How untrusted code is run in isolated, time-limited sandboxes, and why the queue in front of them is the real system.
What this board gets wrong on purpose
The tension
A contest opens and submissions jump from 50 a second to 400 within one minute, but a new worker host takes about three minutes to boot and join, so the spike is over before the autoscaler has helped - the queue absorbs it, and the only real fix on this board is pre-warming the fleet from the contest calendar, which is paid for whether anybody shows up or not. The isolation rule (one fresh microVM per run, never reused) is what makes the warm pool necessary, and a warm pool sized for the peak is mostly idle memory the rest of the day. Verdicts near the time limit are not deterministic: CPU time on a shared host varies by 10 to 15 percent with its neighbours, so the same 1.95 s solution is Accepted on one run and Time Limit Exceeded on the next. And a job lease that expires while a slow run is still going means the scheduler hands it to a second host - the program runs twice, and only the idempotent result write keeps the user from seeing two different verdicts.
Practise this as an interview
Take Code execution sandbox - running a stranger's program as a timed system design interview on a blank board - on your own, with the requirements to check yourself against, or with a candidate you invite.
Start here
Why this design
This is the system behind every online judge, coding interview pad and "run" button in a tutorial. It is asked because it combines two hard things that usually live in different teams: security isolation against a workload that is actively hostile, and queueing under a demand curve that has a cliff in it every time a contest starts. Candidates usually spend the whole hour on Docker flags. The interesting answer spends half of it on the queue.
What you will learn
- Why a container is not a sandbox for untrusted code, and what a microVM (Firecracker, roughly 125 ms cold boot and under 5 MiB of overhead) buys over gVisor and plain namespaces.
- The limits every run gets - CPU time, wall time, memory, processes, output bytes, no network - and which of them actually stop which attack.
- Why one VM per run, never reused, and how a warm pool of snapshot-restored VMs pays for that rule.
- Why the queue is the system: admission, per-user fairness, leases, and why autoscaling cannot catch a contest spike.
- Why verdicts near the time limit are not reproducible, and the three things that make them less wrong.
How to read this board
- Press Play. A submission arrives TOP LEFT, is admitted, and lands in THE QUEUE at the bottom left.
- The scheduler leases it, takes a warm VM and places it on a host in SCHEDULE AND ISOLATE.
- The watchdog enforces the limits; the judge compares output on the RIGHT and the verdict is pushed back.
- Then pages 1 to 6, and the DATA MODEL under them.
- Argue with the weaknesses: the contest spike the autoscaler cannot catch, the idle warm pool, and the 1.95-second solution that passes on Tuesday.
1 · Requirements
Ask these before drawing anything
- Judge or playground? A judge runs a fixed program against hidden test cases and returns a verdict. A playground runs interactively with stdin and maybe a terminal. They share isolation and differ in everything else; this board is a judge.
- Which languages? Each one is a root filesystem image with its own startup cost - C++ is ready in 5 ms, the JVM needs 400 ms before main(), and that startup must not count against the user's time limit.
- Is the time limit CPU time or wall time? CPU time is fairer; wall time catches the program that sleeps or blocks. Use both: CPU for the verdict, wall as the kill.
- Does user code ever need the network? For a judge, no - and "no network device at all" is far stronger than a firewall rule.
- Are there scheduled contests? A known spike can be pre-warmed. An unknown one cannot.
Functional
- Accept a submission (source, language, problem) and return a verdict per test case: Accepted, Wrong Answer, Time Limit, Memory Limit, Runtime Error, Compile Error.
- Report CPU time and peak memory per test case.
- Submitting twice with the same idempotency key creates one submission.
- Push the verdict to the browser; polling is a fallback.
Non-functional
- No submission can read another submission's code, output or test cases, reach the network, or affect the host. This outranks every other requirement.
- Queue wait p95 under 2 s on a normal day, under 30 s during a contest peak.
- A host dying mid-run loses no submission; it is re-run elsewhere.
- Per-user fairness: one user submitting 500 times cannot delay another user's single submission.
Out of scope
- Plagiarism detection.
- Interactive debuggers and terminals.
- GPU workloads.
The rest of this board
Available on Tier Slate
This page publishes the question. The answer — 5 more written pages, an 8-step narrated walkthrough and a 6-table schema — is the board itself, and it opens in Tierslate.
- 5written pages
- 8walkthrough steps
- 6tables40 columns
5 pages behind this one
- Capacity estimation
- Storage estimation
- Availability
- How it works
- Deployment plan
More boards
The building blocks an interview asks you to build from scratch.
- URL shortener - one write, a million reads
- Distributed cache - the ring, and what a node leaving costs
- Key-value store - quorums, and where the consistency knob sits
- Rate limiter - token bucket, and where the counter lives
- Unique ID generator - 64 bits, and two facts nobody can check
- Web crawler - a frontier, and the trap of crawling forever
- Pastebin - a blob store with a short name
- Load balancer - spreading traffic, and noticing who is dead
- API gateway - one front door for many services
- Login and sessions - who you are, on every request
- Feature flags - a config change that ships like code
- Secrets manager - the one store everything trusts
- DNS - the cache that runs the internet
- Distributed cron - exactly one runner at nine o'clock
- Background job queue - at least once, and the retry that doubles it
- Distributed log - Kafka from the partition up
- Consensus - a leader, a log, and a majority
- Object storage - eleven nines from cheap disks