Core Architecture
Lambda + SQS decoupling
Code submission returns 201 immediately and opens an SSE stream. Execution is queued to SQS — deadline bursts queue up without stalling the API. The Lambda worker dequeues and runs the Docker sandbox independently.
AWS LambdaSQS FIFOSSE
Plagiarism Detection
Reframing the problem
"Are two submissions similar?" → "Did this student write this?" Layer 1 scores behavioural signals (paste ratio, speed vs difficulty, tab switches) at exam close. Layer 2 runs TF-IDF cosine only on suspects — O(K×N) not O(N²).
TF-IDFBehavioural signalspre_save signal
AI Agent Design
Async, never on delivery path
All 5 agents are triggered by events but execute fully async — none sit between submission and result. Rubric scoring, hints, and narratives appear after the result is already delivered. Zero latency added to the student experience.
Async queueGPT-4o-miniIdempotent
Code Execution Safety
Docker sandbox isolation
Every submission runs in an isolated Docker container with strict CPU, memory, and time limits enforced by cgroups. No student code can affect another execution or the host. Container killed after the time limit regardless of state.
Dockercgroupstime-limit kill
Concurrency Safety
Attempt gating with row lock
Before accepting a submission, the API checks attempt count using SELECT FOR UPDATE. Prevents race conditions when two tab submissions arrive within milliseconds — common at exam end when every student submits at the same deadline.
PostgreSQLSELECT FOR UPDATE
Real-time Delivery
SSE over WebSocket
Code execution results are unidirectional — server pushes once. SSE chosen over WebSockets for native browser reconnection, HTTP/1.1 proxy compatibility, and simpler Lambda scaling. Redis pub/sub bridges the worker result to the SSE endpoint.
SSEEventSource APIRedis pub/sub