Execution
registerExecutionHandlers — server/socket/handlers/executionHandlers.js
Socket handler for submitting code to the executor and persisting execution results in the database. It depends on EXECUTOR_ADDR for the HTTP call to the execution service and on Prisma for storage.
Server Events
submitCode
Submits a team solution for execution and persistence.
socket.emit("submitCode", {
roomId: string,
code: string,
type: "TWOPLAYER" | "FOURPLAYER",
team?: "team1" | "team2",
teamId?: string,
testCases?: Array<any>,
runIDs?: Array<any>,
submitTime?: string | number | Date,
submitTimer?: string,
});
| Field | Type | Required | Description |
|---|---|---|---|
roomId | string | Yes | Game room ID. |
code | string | Effectively yes | Source code submitted by the team. The validator marks it optional, but execution requires it. |
type | TWOPLAYER | FOURPLAYER | Yes | Game mode. |
team | team1 | team2 | Four-player only | Identifies which team submitted. |
teamId | string | Optional | Socket room for notifying the submitting team. |
testCases | Array<any> | Optional | Fallback game test cases when Redis has none. |
runIDs | Array<any> | Optional | Fallback IDs for the test cases. |
submitTime | string | number | Date | Optional | Submission timestamp source. |
submitTimer | string | Optional | Alternate timestamp string; if blank, the handler falls back to submitTime. |
Behavior
- Validates the payload with Zod.
- Normalizes
submitTimeandsubmitTimerinto a persisted timestamp. - For
TWOPLAYERgames:- Loads the current
gameResultandgameRoom. - Stores the submitted code in
gameResult.team1Codeandteam1SubmittedAt. - Fetches team-generated test cases from Redis via
gameService.getTestCases(team1Id). - Falls back to the event payload if Redis has no test cases.
- Loads hidden tests from
problemTestand normalizes them. - Calls
executeAndPersist(...)once for team 1. - Marks the game finished, emits
gameEnded, cleans up timers, removes players from sockets, and deletes the VM.
- Loads the current
- For
FOURPLAYERgames:- Requires
team. - Deduplicates submissions using Redis key
game:{roomId}:submissions. - Stores the submitting team's code and timestamp in
gameResult. - Waits until both teams have submitted.
- Loads team-specific test cases from Redis, falling back to the payload when needed.
- Loads hidden tests once and normalizes them.
- Executes both teams in parallel with
executeAndPersist(...). - If either execution fails, the game is not finalized and an error is emitted.
- If both succeed, the game is finished, timers are cleaned up,
gameEndedis emitted, sockets are removed, and the VM is deleted.
- Requires
Errors
| Scenario | Result |
|---|---|
| Invalid payload | Emits error with Invalid payload for submitCode. |
Missing roomId | Returns early without emitting a success event. |
Missing gameResult or gameRoom | Emits error with Game or result not found. |
Missing team in four-player mode | Emits error with Missing team for four-player submitCode. |
| Executor request failure | Logs the error and emits a generic socket error from the caller. |
| Persistence failure | Logs the error and emits a generic socket error from the caller. |
submitTestCases
Executes arbitrary test cases for the caller and sends back computed outputs.
socket.emit("submitTestCases", {
roomId: string,
code: string,
testCases: Array<any>,
runIDs: Array<any>,
});
| Field | Type | Required | Description |
|---|---|---|---|
roomId | string | Yes | Game room ID. |
code | string | Yes | Source code to execute. |
testCases | Array<any> | Yes | Test cases to send to the executor. |
runIDs | Array<any> | Yes | Test case IDs passed through to the executor. |
Behavior
- Calls the executor at
EXECUTOR_ADDR/executewithlanguage: "javascript". - Base64-encodes
codebefore sending it. - Returns only the matching results for the provided
testCases. - Emits
receiveTestCaseSynctosocket.teamIdwhen available; otherwise emits to the current socket.
Errors
| Scenario | Result |
|---|---|
| Executor request or parsing failure | Emits error with Sorry that didn't work try again in a few seconds. |
Helper
async executeAndPersist(params): Promise<{ teamNumber: number, totalTests: number, passedCount: number, executionTimeMs: number[], success: true }>
Internal helper used by submitCode to run the executor and persist results.
| Parameter | Type | Description |
|---|---|---|
roomId | string | Game room ID used in the executor payload. |
gameResultId | string | Prisma gameResult ID used for persistence. |
code | string | Submitted source code. |
teamNumber | number | Team being executed, usually 1 or 2. |
testCases | Array<any> | Game test cases to execute. |
testCaseIds | Array<any> | IDs for the game test cases. |
gameRoomId | string | Direct game room reference stored with each gameTest row. |
hiddenTestCases | Array<any> | Hidden test cases to append after the game test cases. Defaults to []. |
hiddenTestCaseIds | Array<any> | IDs for the hidden test cases. Defaults to []. |
Behavior
- Builds a combined execution list from game and hidden tests.
- Sends a POST request to
${EXECUTOR_ADDR}/execute. - Base64-encodes the code and JSON-stringifies the test cases and run IDs.
- Parses
resultsfrom the executor response. - Upserts one
gameTestrow per executed test case. - Persists team-specific columns such as
team1ActualOutput,team1Passed,team2ActualOutput, andteam2Passeddepending onteamNumber. - Returns aggregate metadata including the number of tests, passed count, and per-test execution times.
Errors
| Scenario | Result |
|---|---|
| Executor HTTP failure | Throws an error. |
| Prisma transaction failure | Throws an error. |
Preconditions
EXECUTOR_ADDRmust point to the execution service.- The executor must be available before the handler is invoked.
- Database access must be available for persistence.
- The executor can only accept json
Postconditions
- Successful submissions persist
gameTestrows for both game and hidden tests. - Completed games emit
gameEndedand are marked finished. submitTestCasesreplies with computed outputs for the requested cases.