•CASE STUDY

Online Judge and Coding Contest Platform (LeetCode)

7 min read·1,212 words·Intermediate

Asked at

8 candidate reports between Dec 2025 and Jun 2026

How to use this case study

SDE-2 / Mid

  • Explain the submission flow (queue, runner, verdict)
  • How test cases are stored
  • How the user gets the result

SDE-3 / Senior

  • Go deeper on sandboxing untrusted code
  • Resource limits
  • Autoscaling runners for contest spikes
  • Computing a live leaderboard

Staff / Principal

  • Discuss fairness and determinism of timing
  • Multi-language runtimes
  • Cost control
  • Plagiarism detection and running contests with 100K+ participants

Problem RestatementProblem

Design a platform like LeetCode or Codeforces. Users browse problems, write code in the browser in many languages, and submit it. The system runs the code against hidden test cases and returns a verdict: Accepted, Wrong Answer, Time Limit Exceeded, Runtime Error or Compilation Error. Contests add a timer, a burst of submissions at the start and end, and a live leaderboard.

The hardest part is that we run untrusted code from strangers, so it must be isolated and limited.

RequirementsRequirements

1.1 Functional

  • Browse and search problems, and view statements and examples.
  • Run code against sample tests, and submit against hidden tests.
  • Get a verdict with runtime and memory.
  • Contests: registration, timed window, scoring and a live leaderboard.
  • Submission history.

1.2 Non-Functional

  • Security: user code can never reach the network, other users' data or our servers.
  • Fairness: same code gives the same verdict and similar timings.
  • Fast feedback: verdict in a few seconds normally.
  • Handle spikes: contest start or end can bring 10x traffic.

1.3 Scale Estimates

  • 5M daily users, 2M submissions/day ≈ 25/sec average.
  • Contest with 50K participants: in the last 10 minutes, maybe 1,000 submissions/sec.
  • Each submission runs ~50 tests, taking 2–10 seconds of CPU in total. At 1,000/sec, that is 2,000–10,000 CPU cores busy, so runners must autoscale.

1.4 API Design

POST/v1/submissions{ problem_id, language: "python3", code, contest_id? } → { submission_id, status: "queued" }
GET/v1/submissions/{id}→ { status, verdict, runtime_ms, memory_kb, failed_test? } (or a WebSocket push)
GET/v1/contests/{id}/leaderboard?page=1

High-Level ArchitectureArchitecture

2.1 Overview

  • Problem Service: problems, statements and sample tests (cached heavily and served via CDN).
  • Submission Service: saves the submission and puts a job on the queue.
  • Queue: separate queues for contest submissions (priority) and practice.
  • Runner fleet: workers that compile and run code inside a sandbox against test cases.
  • Test case store: hidden test files in object storage, cached on runners.
  • Result delivery: updates the DB and pushes the verdict to the user.
  • Leaderboard Service: updates contest rankings from accepted results.

2.2 Architecture Diagram

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
    U["User browser"] --> API["Submission Service"]
    API --> DB[("Submissions DB")]
    API --> Q[("Job queue - contest priority")]
    Q --> R1["Runner - sandbox"]
    Q --> R2["Runner - sandbox"]
    TC[("Hidden test cases - object storage")] --> R1
    TC --> R2
    R1 -->|"verdict"| RES["Result handler"]
    R2 -->|"verdict"| RES
    RES --> DB
    RES -->|"push"| U
    RES --> LB["Leaderboard Service"]
    LB --> RD[("Redis sorted set")]

Data ModelData model

problems:     problem_id, title, statement, difficulty, time_limit_ms, memory_limit_mb, tests_version
submissions:  submission_id, user_id, problem_id, contest_id, language, code_ref,
              status (queued, running, done), verdict, runtime_ms, memory_kb, created_at
contest_scores: contest_id, user_id, score, penalty, solved_count, last_accepted_at

Key FlowsFlows

4.1 Submit

  1. Save the submission (code in object storage or DB) with status queued.
  2. Push a job { submission_id } to the queue. Return right away.
  3. A runner takes the job, loads the code and the problem's tests (cached locally by tests_version), compiles if needed, and runs each test inside a sandbox with limits.
  4. It stops at the first failing test (as most judges do), and returns the verdict with time and memory.
  5. The result handler saves the verdict and pushes it to the user over WebSocket (or the client polls every second).

4.2 Leaderboard update

When an accepted verdict arrives during a contest, update the user's score (points, plus a penalty for time and wrong tries) in a Redis sorted set, a structure that keeps items ordered by score. Reading the top 100 is then instant.

Deep Dive A — Running code a stranger wroteDeep dive

Every submission is arbitrary code from an anonymous user, and it runs on our machines. Assume it is hostile: it will try to read other submissions, reach the network, fork forever and never exit.

Weak

Run it as a process with a timeout

Write the file to /tmp, run the compiler, run the binary with a wall-clock timeout, capture stdout.

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  S["Submitted code"] --> P["Process on the runner host"]
  P --> F1["Reads /etc and other submissions"]
  P --> F2["Opens a socket - exfiltrates or attacks"]
  P --> F3["fork bomb - host unusable"]
  P --> F4["Writes 40 GB to disk"]

A timeout bounds one thing and nothing else. The process shares a file system with every other submission, has the network, and can spawn children that outlive the parent the timeout kills.

Good

A container per submission with resource limits

Run each submission in a fresh container: its own file system and process namespace, a CPU quota and a memory cap through cgroups, a PID limit that stops fork bombs, no network, an unprivileged user with capabilities dropped.

This closes almost everything and is a defensible answer. What is left is that containers share the host kernel. A kernel escape — and they surface regularly — is a full compromise of the runner, and the code running against it was written specifically to try. That risk is acceptable for a build farm you own and not for a public judge.

Best

A kernel boundary, and destroy it afterwards

Put a kernel between the submission and the host: gVisor, which intercepts system calls in userspace, or a Firecracker microVM with its own kernel and a ~100 ms boot.

Architecture diagram
%%{init: {"look":"handDrawn","handDrawnSeed":7,"theme":"base","fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","themeVariables":{"fontFamily":"Virgil, \"Segoe Print\", \"Comic Sans MS\", cursive","fontSize":"16px","primaryColor":"#fff4e6","primaryBorderColor":"#1e1e1e","primaryTextColor":"#1e1e1e","secondaryColor":"#e7f5ff","tertiaryColor":"#ebfbee","lineColor":"#1e1e1e","textColor":"#1e1e1e","mainBkg":"#fff4e6","nodeBorder":"#1e1e1e","clusterBkg":"#f8f9fa","edgeLabelBackground":"#ffffff","classText":"#1e1e1e"}}}%%
flowchart LR
  SUB["Submission"] --> VM["Firecracker microVM - own kernel"]
  VM --> LIM["cgroups - CPU time, 256 MB, PID cap, output cap"]
  VM --> RO["Read-only rootfs + small tmpfs"]
  VM --> NONET["No network device"]
  VM --> SEC["seccomp - dangerous syscalls blocked"]
  VM --> DESTROY["Destroyed after the run - nothing survives"]

The sandbox is destroyed after every submission rather than reset, so nothing a run leaves behind can reach the next one. Layer the limits anyway — the microVM is the boundary, the cgroup limits and seccomp filters are what stop a run from ruining the host's day without escaping anything.

One thing this does not fix: timing. A container that has to share a core reports different CPU times run to run, which is the next deep dive.

Deep Dive B — Fair timing and contest spikesDeep dive

  • Fair timing: measure CPU time, not wall-clock time. Pin each run to a dedicated CPU core, avoid running too many jobs on one machine, and use the same machine type for all runners. For borderline results, re-run a few times and take the minimum.
  • Autoscaling: pre-warm extra runners before a contest starts, because they take minutes to boot. Also autoscale on queue length.
  • Priority: contest jobs go first. Practice submissions may wait a little longer during contests.
  • Test cache: runners keep test files on local disk, keyed by tests_version, so there's no download per submission.

Trade-offs & AlternativesTrade-offs

DecisionChoiceWhyAlternative
ExecutionAsync queue + runnersAbsorbs spikes, retriesRun inside the API request: timeouts, unsafe
SandboxgVisor / FirecrackerStrong isolationPlain Docker: faster, weaker isolation
Result deliveryWebSocket push (polling fallback)Instant feedbackPolling only: simple, more load
LeaderboardRedis sorted setO(log n) updates, fast top-NSQL ORDER BY: slow at contest scale

Common Follow-up QuestionsFollow-ups

  • "How do you support 20 languages?" One runner image per language (or one image with all toolchains), each with language-specific time multipliers (e.g., Python gets extra time).
  • "How do you detect plagiarism?" After the contest, compare submissions with token-based similarity tools (like MOSS) and flag suspicious pairs for review.
  • "How do you avoid leaking hidden tests?" Don't return full failing inputs for hidden tests in contests. Only show the test number.

Wrap-UpWrap-up

Save each submission and queue it, and let an autoscaled runner fleet execute code in isolated sandboxes (gVisor or Firecracker) with no network and strict CPU and memory limits. Measure CPU time on dedicated cores for fairness, push verdicts back over WebSockets, and keep contest rankings in a Redis sorted set. Pre-warm runners and prioritize contest jobs to survive spikes.

More Case Studies

Frequently Asked Questions

What is the Online Judge and Coding Contest Platform (LeetCode) system design question?

Online Judge and Coding Contest Platform (LeetCode) is a system design interview question asked at FAANG companies. It covers distributed systems, security, scheduling, real-time and tests your ability to design scalable, production-ready systems. InterviewSkool's breakdown walks you through requirements, API design, architecture, and trade-offs.

Which companies ask the Online Judge and Coding Contest Platform (LeetCode) question?

Flipkart, Google, Meta have reportedly asked variations of this question in system design interviews. The exact wording may differ, but the core design challenges remain the same.

How should I prepare for the Online Judge and Coding Contest Platform (LeetCode) interview question?

Start with the problem statement and scale estimates, then design the high-level architecture. Focus on the core components, data model, and API design. InterviewSkool's breakdown covers the full solution with mermaid diagrams and trade-off analysis to help you prep efficiently.

What level is the Online Judge and Coding Contest Platform (LeetCode) question?

This question is suitable for SDE-2, SDE-3, and Staff engineer interviews. The level guidance on this page provides specific tips for each level — SDE-2 candidates should focus on core architecture, while Staff engineers should discuss trade-offs, monitoring, and incremental rollouts.

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with InterviewSkool's AI interviewer.

Start System Design Interview →