Learning pathsPricingA
SOLUTION REVIEW

Review: LeetCode

Design an online code judge that executes untrusted submissions.

Clarify this prompt before choosing components

Ask the highest-impact questions first, agree on priorities, and record the interviewer’s answers. If a detail is unspecified, state an assumption and explain which decision depends on it. The numbers in this worked lesson are exercise assumptions, not company facts.

Ask the interviewerWhy the answer changes the design
Code execution, submissions or timed contests first?Contest deadlines/leaderboards add fairness and ordering rules.
Languages, time/memory limits and untrusted code?Use isolation, resource budgets and bounded output.
Can a submission be rejudged after tests change?Pin judge versions and define result revision semantics.

Use the Interview Playbook for the shared 45-minute sequence and fresher, intermediate, senior and staff evidence. Start with one complete operation. Extend the answer with the failure/recovery traces below, then defend a workload-specific alternative and a measurable rollout. Scope and evidence matter more than a large component list.

LeetCode: Understand the building blocks

Choose a mechanism because it satisfies a requirement. These explanations describe the exercise design, not undisclosed implementation choices at the named company.

LeetCode: Quick vocabulary

TermMeaning and role in this exercise
API: Application Programming InterfaceThe contract for requests, responses and errors between components. An API route does not itself enforce every business invariant.
CPU: Central Processing UnitGeneral-purpose compute whose time/concurrency must be bounded for judging, processing or encoding.
PK: Primary KeyThe declared row identity in a database schema; it does not automatically enforce every cross-row business rule.
OOM: Out of MemoryA process cannot satisfy an allocation or is terminated by its resource policy. Bound inputs and actually reclaim failed worker resources.

LeetCode: Sandbox and resource isolation

What it means: A sandbox restricts untrusted program execution through an explicit isolation boundary, privileges and resource/network policies.

Why this problem needs it: Submitted code is untrusted and may loop or allocate indefinitely.

How to use it: Run a pinned submission/test version in an isolated process/container/VM boundary, constrain CPU, memory, output and wall time, and actually terminate runaway execution.

Example in this design: Kill a runaway execution at the actual resource boundary; do not only mark its job timed out.

When it fits: Required when evaluating user code instead of trusting it as ordinary application code.

Alternative and limits: Do not execute untrusted code inside the web process. A container name or timeout flag alone does not prove isolation or resource reclamation.

LeetCode: Durable work queue and backpressure

What it means: A queue separates accepted work from execution. Backpressure limits admission or consumption when downstream capacity is finite.

Why this problem needs it: Judging should absorb a finite submission burst without blocking request threads.

How to use it: Persist a stable job identity, consume with bounded concurrency, acknowledge after the required durable transition, and cap retries/backlog according to policy.

Example in this design: A submission returns a durable job identity while bounded workers run the pinned suite.

When it fits: Useful for asynchronous work that must survive worker failure or absorb a finite burst.

Alternative and limits: A synchronous call is simpler for short bounded work. A queue does not create capacity, strict global ordering or exactly-once external effects.

LeetCode: Lease, ownership epoch and fencing

What it means: A lease grants temporary work ownership. A fencing token or epoch identifies a newer owner so stale owners can be rejected at the mutation boundary.

Why this problem needs it: A stale judge must not overwrite a newer verdict attempt.

How to use it: Claim a job under an atomic authority, increment its attempt/epoch, and require that value on result publication. The protected resource must enforce the check.

Example in this design: After attempt 10 owns the job, attempt 9 cannot publish a verdict.

When it fits: Useful when workers can pause, restart or overlap after a timeout.

Alternative and limits: A non-expiring lock risks blocking forever. Lease expiry alone cannot stop an old process that resumes; external effects need their own supported idempotency/reconciliation.

LeetCode: Projection and materialized view

What it means: A projection is a derived read model built from authoritative facts; it improves a particular read path and can be rebuilt.

Why this problem needs it: Leaderboard reads should not rerun all judging history.

How to use it: Consume versioned facts with replay-safe updates, expose a watermark/revision, and compare or rebuild from the authoritative history.

Example in this design: A verdict revision updates a replay-safe score view; duplicate delivery cannot add points again.

When it fits: Useful when read shapes or volume justify duplicating computation/state.

Alternative and limits: Read authoritative rows directly for a simpler strongly current baseline. A stale projection must not grant revoked access or decide a strict inventory transition.

Interview scope and guarantees

Browse problems, submit source code, execute hidden tests, return verdicts, and rank contest participants. Untrusted code must not access host resources, credentials, other submissions, or the network. Define CPU, memory, output, and wall-time limits separately.

Capacity worksheet

Assume 100,000 contestants submit once every 2 minutes: about 833 submissions/s. At 2 CPU-seconds/submission the workload consumes about 1,667 fully utilized CPU cores; headroom, startup and heavy languages increase the requirement. Polling 100,000 users every 5 seconds creates 20,000 status reads/s, motivating cached verdicts and backoff.

Concrete API contract

Contract / pseudocode
POST /submissions {problemId,language,source,contestId?} -> 202 {submissionId}
GET /submissions/{id} -> {state,verdict,runtime}
GET /contests/{id}/leaderboard?cursor=...
POST /submissions/{id}/cancel

Data model and access paths

Contract / pseudocode
submissions(id PK,user_id,request_key,request_hash,problem_version,source_key,state,generation); UNIQUE(user_id,request_key)
results(submission_id UNIQUE,judge_version,verdict,cpu_ms,memory_bytes)
first_solves(contest_id,user_id,problem_id,accepted_at); PK(contest_id,user_id,problem_id)
contest_scores(contest_id,user_id,score,penalty,version); PK(contest_id,user_id)
execution_leases(submission_id PK,generation,expires_at)

Evolve a solution and explain each change

Three architecture decisions for LeetCode, including the pressure each introduces.
Three architecture decisions for LeetCode, including the pressure each introduces.
Read the diagram

Run one submission / Persist code and return a submission ID before execution. / Executing untrusted code inside the API process is unsafe.; Use isolated workers / Compile and run in restricted sandboxes with CPU, memory, time, and output limits. / Workers can crash and queues can deliver the same submission twice.; Fence attempts / Lease jobs with attempt tokens and publish a result only for the current attempt. / A stale worker must not overwrite a newer accepted result.

Open original
LeetCode · architecture decisions
Three architecture decisions for LeetCode, including the pressure each introduces.

Three architecture decisions for LeetCode, including the pressure each introduces.

Step 1: Run one submission

Persist code and return a submission ID before execution. Executing untrusted code inside the API process is unsafe.

Step 2: Use isolated workers

Compile and run in restricted sandboxes with CPU, memory, time, and output limits. Workers can crash and queues can deliver the same submission twice.

Step 3: Fence attempts

Lease jobs with attempt tokens and publish a result only for the current attempt. A stale worker must not overwrite a newer accepted result.

Responsibility overview

Connected responsibilities for LeetCode. Trace the authoritative and derived paths separately.
Connected responsibilities for LeetCode. Trace the authoritative and derived paths separately.
Read the diagram

Student to Submission API: submit source; Submission API to Result DB: commit submission; Result DB to Job queue: job intent; Job queue to Job dispatcher: lease job; Job dispatcher to Sandbox: run restricted tests; Job dispatcher to Result DB: fenced attempt result

Open original
LeetCode · connected architecture
Connected responsibilities for LeetCode. Trace the authoritative and derived paths separately.

Connected responsibilities for LeetCode. Trace the authoritative and derived paths separately.

Worked end-to-end scenario

A student submits code and receives s42. The queue delivers s42 to worker W1, which leases attempt 1. W1 stalls after compiling; its lease expires and W2 starts attempt 2. W1 eventually reports success. The result update includes attempt 1, so it is rejected as stale. W2 runs the fixed test-set version under resource limits and commits the authoritative result for attempt 2. The interface polls or receives a notification after commit. Hidden-test contents remain inside the execution boundary; compiler output is capped and escaped before display.

Why these access paths matter

Submission reads use the student and submission ID; execution uses a pinned problem/test-set version and language image. Index queued or expired attempts by availability time. The queue message names durable state, not the only copy of code. Record compile errors separately from resource-limit failures and incorrect answers so the same verdict does not conceal different mechanisms.

Build the baseline first

LeetCode: baseline request paths.
LeetCode · working baseline
Read the diagram

Submit API → submission and outbox → work queue; Runner → isolated sandbox → versioned tests; Result commit → status read → user

Open original
LeetCode · working baseline
LeetCode: baseline request paths.

LeetCode · working baseline

  1. Submit API → submission and outbox → work queue.
  2. Runner → isolated sandbox → versioned tests.
  3. Result commit → status read → user.

Evolve the design under load

LeetCode: additional scaling and recovery paths.
LeetCode · scale and recovery paths
Read the diagram

Fair queues → language pools → bounded sandbox slots; Result events → score projector → sorted ranking; Immutable source and tests → object storage

Open original
LeetCode · scale and recovery paths
LeetCode: additional scaling and recovery paths.

LeetCode · scale and recovery paths

  1. Fair queues → language pools → bounded sandbox slots.
  2. Result events → score projector → sorted ranking.
  3. Immutable source and tests → object storage.

Defend the hardest decision

Containers share a kernel; a high-assurance judge may use stronger isolation such as microVMs. Apply namespaces, unprivileged identity, syscall restrictions, read-only images, no ambient credentials, disabled egress, and cgroup resource limits. CPU time and wall time catch different abuses. Limit child processes, output size, filesystem usage and compilation time. Test fixtures and expected answers must remain outside user-readable paths.

Failure and recovery analysis

A worker exceeds its lease but continues executing. A new attempt receives a higher generation; the result store accepts only the currently valid generation. Killing the old sandbox limits cost, while fencing prevents stale results from winning. A contest score update must be idempotent by accepted result identity, not by blindly incrementing a score after each queue delivery.

Security and privacy boundary

Never execute learner source in the web server process. Separate judge workers from production secrets and test sandbox escape scenarios before enabling real execution.

Interview follow-ups with reasoning

Question: Why does a Redis sorted set not solve all ranking?

Show answer and explanation

Answer: Tie-break rules, score recalculation, and durable recovery still need authoritative records.

Question: How do you absorb contest bursts?

Show answer and explanation

Answer: Queue fairly, report estimated wait, and cap per-user outstanding submissions.

Question: What if the judge version changes?

Show answer and explanation

Answer: Store problem and judge versions so rejudging is auditable.

Operate and verify the design

Queue wait by language, sandbox startup, resource-limit kills and stale-result rejections.

Pause a runner past lease expiry, start a new attempt and verify that the old result cannot win.

Compare alternatives

BoundaryProtectionReason
User to APIQuota and source limitsAdmission control
Runner to codeIsolation and resource limitsUntrusted execution
Attempt to resultFencing tokenReject stale completion
Test versionImmutable referenceReproducible judging

Design workshop: judging and ranking are different pipelines

Core flows are problem lookup, source submission, judged result and contest leaderboard. A production editor and interactive debugger are extensions. Assume result status is observable within five seconds for small tests under admitted load, leaderboard freshness within five seconds and no stale worker can publish a final verdict. A timeout is a verdict only under the pinned execution policy, not a queue-delay measurement.

Store source and signed immutable test manifests in object storage. The admission transaction creates submission(user_id,request_key,request_hash,problem_version,source_key), unique by user/request, and an outbox event. A retry returns the original submission; a changed source under the same key returns 409. Workers fetch the pinned language image/test version. Compile, execute and compare are separate phases with separate time/memory/output budgets. Compilation failure returns a sanitized diagnostic; expected answers never enter user-readable paths. A trusted comparator reads capped output after the sandbox stops. It cannot run an arbitrary contestant-supplied comparator.

Judge result to durable score projection. Submission API to Result DB: Persist source reference, submission and outbox; Sandbox scheduler to Result DB: Claim attempt generation 5 and lease; Sandbox scheduler to Sandbox scheduler: Compile then run pinned tests under resource limits; Sandbox scheduler to Result DB: Commit verdict only if generation 5 still current; Result DB to Score projector: Accepted-result event with stable identity; Score projector to Score projector: Recompute user score; versioned absolute ZADD
Judge result to durable score projection.
Read the diagram

Persist source reference, submission and outbox; Claim attempt generation 5 and lease; Compile then run pinned tests under resource limits; Commit verdict only if generation 5 still current; Accepted-result event with stable identity; Recompute user score; versioned absolute ZADD

Open original
Judge result to durable score projection
Judge result to durable score projection. Submission API to Result DB: Persist source reference, submission and outbox; Sandbox scheduler to Result DB: Claim attempt generation 5 and lease; Sandbox scheduler to Sandbox scheduler: Compile then run pinned tests under resource limits; Sandbox scheduler to Result DB: Commit verdict only if generation 5 still current; Result DB to Score projector: Accepted-result event with stable identity; Score projector to Score projector: Recompute user score; versioned absolute ZADD

Judge result to durable score projection.

For a 90-minute contest choose: more distinct solved problems wins; equal solve counts use smaller sum of first accepted solve times since contest start; remaining ties use user ID. This is a concrete scenario policy, not a claim about LeetCode's actual scoring. With ten problems and durations at most 5,400 seconds, total penalty is at most 54,000. Define score = solved×54,001 + (54,000−penalty). Redis ZRANGE board 0 99 REV returns higher scores first. Equal numeric scores need an explicit user-ID tie policy; Redis reverse lexicographic member order can be selected or an application tie layer can impose ascending IDs.

python
# Durable score transaction: result delivery can repeat.
if insert_or_lower_first_solve_time(contest, user, problem, accepted_at):
    solved, penalty = recompute_from_first_solves(contest, user)
    version = increment_score_version(contest, user)
    emit_score_event(user, solved * 54001 + 54000 - penalty, version)
# Projection uses Lua: ignore version <= applied version,
# then ZADD the absolute score and store the version atomically.

Unique(contest,user,problem) prevents repeated accepted submissions increasing solved count. If an earlier accepted result arrives late, conditionally lower first_solve_time and recompute even when the row exists. Score updates carry per-user versions; an old event cannot overwrite a newer absolute score. Contest/problem ownership makes first-solve timing unambiguous. Store accepted submission time rather than result completion time if the product chooses that rule, and state the cutoff behavior for queued work after contest end.

Leaderboard worked example. A / 3 solved; 1,200 seconds penalty / 214,803; ahead of B; B / 3 solved; 1,400 seconds penalty / 214,603; behind A; C / 2 solved; 10 seconds penalty / 161,992; behind either 3-solve user; A retry / Same accepted problem delivered again / Unchanged first-solve identity and score
Leaderboard worked example.
Read the diagram

User / Solved + penalty / Score and rank; A / 3 solved; 1,200 seconds penalty / 214,803; ahead of B; B / 3 solved; 1,400 seconds penalty / 214,603; behind A; C / 2 solved; 10 seconds penalty / 161,992; behind either 3-solve user; A retry / Same accepted problem delivered again / Unchanged first-solve identity and score

Open original
Leaderboard worked example
Leaderboard worked example. A / 3 solved; 1,200 seconds penalty / 214,803; ahead of B; B / 3 solved; 1,400 seconds penalty / 214,603; behind A; C / 2 solved; 10 seconds penalty / 161,992; behind either 3-solve user; A retry / Same accepted problem delivered again / Unchanged first-solve identity and score

Leaderboard worked example.

Rebuild a missing leaderboard from first-solves at watermark W, write a new Redis key, replay changes after W and atomically switch the read alias. Database writes and Redis writes are not one transaction; outbox and versioned projection bridge them. At 100,000 viewers polling every five seconds, serve 20,000 reads/s from a cache/replicated read tier rather than aggregate submissions for every read. Partition contests, bound leaderboard pages and report snapshot version. Do not broadcast every score update to every participant unless the product needs it.

Use per-language queues with tenant/user admission quotas and weighted scheduling. Set example budgets such as 2 CPU seconds, 5 wall seconds, 256 MiB, 32 processes and 1 MiB stdout, then tune per problem; these are illustrative limits, not universal safe defaults. Cancellation revokes current attempt ownership and kills the sandbox, but consumed CPU still counts. A stale result fails its conditional commit. Track queue wait separately from compile/run latency.

Exercise: A has an accepted solve at second 500, delivered twice, then an earlier valid solve at second 450 arrives. What changes?

Show answer and explanation

Answer: One solved problem remains. First-solve penalty falls by 50 seconds, a new score version is emitted and the absolute score increases by 50. Blind ZINCRBY on every event would overcount.

Redis sorted sets documents ranking primitives; first-solve semantics, version checks and rebuilds belong to this application.

Requirement trace and verification

RequirementImplementing design blockVerification link
R1 — Complete the primary user journey within the stated scope.P01–P04; P09–P10.V1 — Exercise the successful journey and the excluded/boundary case stated in the scope.
R2 — Preserve the problem's authoritative data invariant under concurrency.P05–P06; P11–P12; DD1.V2 — Run the race/replay case below and assert the invariant at the durable authority.
R3 — Meet the declared scale and API behavior without unbounded work.P05–P08; P13–P14; relevant overload deep dives.V3 — Exercise the API errors/retry identity and recompute the workload assumption that drives partition or capacity.
R4 — Recover from the named failure without losing or duplicating the user-visible outcome.P15–P16; deep dives; Operations contract.V4 — Replay accepted submissions, kill a worker, submit an infinite loop, and restart ranking storage; no double credit or cross-submission data leakage.

Operational contract

AreaDecision and signals
SLIsQueue wait by language; sandbox startup; timeout/OOM rate; stale attempt results; leaderboard projection lag.
Overload limitsCap queued submissions, concurrent sandboxes, CPU/memory/process/output/time, and leaderboard reads.
RecoveryFence attempts by generation; requeue after lease expiry; rebuild rankings from durable accepted-solve records.
Access controlsKeep hidden tests and secrets outside the client; use isolated no-network workers with no app credentials.
Dominant costSandbox compute and hidden-test storage/egress.

Senior-level interviewer follow-ups

Question: A contestant cancels while a sandbox process is still running. What stops a late verdict?

Show answer and explanation

Answer: Revoke the attempt generation and kill the process, then require the same current generation at result commit. Cancellation saves future work, while fencing protects correctness even if termination is delayed.

Question: How do you protect hidden tests from the submission and compiler output?

Show answer and explanation

Answer: Pin immutable test manifests outside learner-readable paths, isolate execution without ambient credentials or network egress, cap output, and sanitize compiler diagnostics before display.

A 60-second design answer

I would persist each submission and return its ID before execution. A durable queue feeds isolated, resource-limited runners pinned to a language image and test version. Attempts have leases and generations so stale workers cannot commit. Accepted results update a durable first-solve record; a versioned projector rebuilds the contest leaderboard. I would separate queue delay from compile/run time and test sandbox escape boundaries.

Managing Long Running Tasks PostgreSQL

Technical references

PostgreSQL transaction isolation and concurrent updates.

Identify which attempt may publish a score

Submission s7 references immutable problem/test/language versions. A runner under epoch 9 stops heartbeating; epoch 10 replaces it. Results from 9 are rejected at publication. One accepted result revision updates the competition score using s7's identity, so redelivery cannot increment the leaderboard twice.

Contract / pseudocode
s7: input/test/runtime versions frozen
attempt 9: lease lost
attempt 10: result accepted
late result 9: rejected
score contribution s7: applied once
s7: input/test/runtime versions frozen; attempt 9: lease lost; attempt 10: result accepted; late result 9: rejected; score contribution s7: applied once
Identify which attempt may publish a score
Read the diagram

s7: input/test/runtime versions frozen; attempt 9: lease lost; attempt 10: result accepted; late result 9: rejected; score contribution s7: applied once

Open original
Identify which attempt may publish a score
s7: input/test/runtime versions frozen; attempt 9: lease lost; attempt 10: result accepted; late result 9: rejected; score contribution s7: applied once

Identify which attempt may publish a score

Untrusted code has bounded CPU, wall time, memory, process count, output and storage. Restrict network and syscall surface, use appropriate sandbox/VM/container isolation, and keep secrets and hidden-test material outside the submitted program's accessible environment. A container label alone is not a security proof. Separate trusted test orchestration from the code process and treat output as untrusted data.

Redis sorted sets can serve bounded leaderboard pages under the declared tie/scoring rules; authoritative results enable repair. Polling every five seconds for 100,000 users is about 20,000 requests/s before caching, so coalesce/cache eligible competition snapshots and bound runner admission separately.

Show answer and explanation

Answer: Reusing s7 dedupes result/score publication, while the attempt epoch decides current ownership. These solve different replay and stale-worker failures.

Decision review: LeetCode

LeetCode: What it is

A judging service accepts a submission and produces a result under pinned language, runtime and test-suite versions.

LeetCode: Why it is needed

User code is untrusted and may consume resources or attack the execution boundary; a timed-out API is not proof that execution stopped.

LeetCode: When to use it

Use isolated asynchronous execution for variable or hostile work. Choose isolation strength from the threat model, beyond merely starting a container.

LeetCode: How to use it

Persist a submission and bounded job. Enforce CPU, memory, process, network and output limits at the execution boundary. Publish results only for the current attempt and pinned judge inputs.

LeetCode: Compare an alternative

One sandbox per job improves isolation but costs startup time. Reused workers require a demonstrably safe reset. Stronger isolation may be necessary for hostile tenants and cannot be inferred from a container label.

LeetCode: Worked decision exercise

The following inputs and policies are original exercise assumptions; they are not measurements or undisclosed company behavior.

Attempt 9 runs submission s7 against suite v3, loses its lease, then completes late. Attempt 10 runs the same pinned inputs and publishes. A delayed attempt 9 must not replace its verdict or independently increment a leaderboard.

LeetCode: Submission s7 pins runtime and test suite v3; Attempt 9 loses lease; attempt 10 is current; Sandbox enforces resources, not the API timeout; Publication rejects a late attempt 9 verdict
LeetCode: a concrete state and recovery trace under the exercise assumptions.
Read the diagram

Submission s7 pins runtime and test suite v3; Attempt 9 loses lease; attempt 10 is current; Sandbox enforces resources, not the API timeout; Publication rejects a late attempt 9 verdict

Open original
LeetCode: worked example
LeetCode: Submission s7 pins runtime and test suite v3; Attempt 9 loses lease; attempt 10 is current; Sandbox enforces resources, not the API timeout; Publication rejects a late attempt 9 verdict

LeetCode: a concrete state and recovery trace under the exercise assumptions.

How do you distinguish a program timeout from a broken judge worker?

Show answer and explanation

Answer: Record resource termination and infrastructure failure separately. A verdict reflects the pinned test contract; an infrastructure retry uses the same submission identity and a newer attempt epoch. Result fencing must be enforced at publication, while the process tree is actually terminated by the sandbox boundary.

LeetCode: Check the design

Monitor queue wait, per-language execution cost, output truncation, isolation failures and stale publication rejections. Pin the test version so rejudging is explainable.

Your study notes