improved faster backend with input output

This commit is contained in:
2025-03-25 21:45:29 +05:30
parent c906cd8684
commit 6c6ab17203
10 changed files with 426 additions and 169 deletions

View File

@@ -1 +1 @@
SERVER_URL="http://localhost:8000" VITE_API_URL="https://monacoapi.thearnab.tech"

View File

@@ -714,7 +714,7 @@ Happy coding!`;
title="Run code" title="Run code"
> >
{isRunning ? <Loader size={16} className="animate-spin" /> : <Play size={16} />} {isRunning ? <Loader size={16} className="animate-spin" /> : <Play size={16} />}
<span>Run</span>
</button> </button>
<button <button
className="terminal-toggle-button" className="terminal-toggle-button"

View File

@@ -836,10 +836,11 @@ body {
.run-button { .run-button {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 4px 8px; padding: 4px 4px;
margin-right: 8px; margin-right: 8px;
background-color: #3c3c3c; background-color: #1e1e1e;
color: #cccccc; color: #cccccc;
border: none; border: none;
border-radius: 3px; border-radius: 3px;
cursor: pointer; cursor: pointer;

View File

@@ -4,6 +4,7 @@ import (
"encoding/json" "encoding/json"
"net/http" "net/http"
"sync" "sync"
"time"
"github.com/arnab-afk/monaco/model" "github.com/arnab-afk/monaco/model"
"github.com/arnab-afk/monaco/service" "github.com/arnab-afk/monaco/service"
@@ -79,7 +80,34 @@ func (h *Handler) StatusHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
json.NewEncoder(w).Encode(map[string]string{"status": submission.Status}) // Return status with time information
response := map[string]interface{}{
"id": submission.ID,
"status": submission.Status,
}
// Add time information based on status
if !submission.QueuedAt.IsZero() {
response["queuedAt"] = submission.QueuedAt.Format(time.RFC3339)
}
if submission.Status == "running" && !submission.StartedAt.IsZero() {
response["startedAt"] = submission.StartedAt.Format(time.RFC3339)
response["runningFor"] = time.Since(submission.StartedAt).String()
}
if submission.Status == "completed" || submission.Status == "failed" {
if !submission.CompletedAt.IsZero() && !submission.StartedAt.IsZero() {
response["executionTime"] = submission.CompletedAt.Sub(submission.StartedAt).Milliseconds()
response["completedAt"] = submission.CompletedAt.Format(time.RFC3339)
}
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to serialize response: "+err.Error(), http.StatusInternalServerError)
return
}
} }
// ResultHandler handles result requests // ResultHandler handles result requests
@@ -99,7 +127,56 @@ func (h *Handler) ResultHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
json.NewEncoder(w).Encode(map[string]string{"output": submission.Output}) // Prepare response with safe time handling
response := map[string]interface{}{
"id": submission.ID,
"status": submission.Status,
"output": submission.Output,
"language": submission.Language,
}
// Only include time fields if they're set
if !submission.QueuedAt.IsZero() {
response["queuedAt"] = submission.QueuedAt.Format(time.RFC3339)
}
if !submission.StartedAt.IsZero() {
response["startedAt"] = submission.StartedAt.Format(time.RFC3339)
}
if !submission.CompletedAt.IsZero() {
response["completedAt"] = submission.CompletedAt.Format(time.RFC3339)
// Calculate times only if we have valid timestamps
if !submission.StartedAt.IsZero() {
executionTime := submission.CompletedAt.Sub(submission.StartedAt)
response["executionTime"] = executionTime.Milliseconds() // Use milliseconds for frontend
response["executionTimeFormatted"] = executionTime.String()
}
if !submission.QueuedAt.IsZero() {
totalTime := submission.CompletedAt.Sub(submission.QueuedAt)
response["totalTime"] = totalTime.Milliseconds() // Use milliseconds for frontend
response["totalTimeFormatted"] = totalTime.String()
}
}
// Return full submission details
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, "Failed to serialize response: "+err.Error(), http.StatusInternalServerError)
return
}
}
// QueueStatsHandler provides information about the job queue
func (h *Handler) QueueStatsHandler(w http.ResponseWriter, r *http.Request) {
stats := h.executionService.GetQueueStats()
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"queue_stats": stats,
"submissions": len(h.submissions),
})
} }
// generateID creates a unique ID for submissions // generateID creates a unique ID for submissions

View File

@@ -50,6 +50,7 @@ func main() {
http.HandleFunc("/submit", corsMiddleware(loggingMiddleware(h.SubmitHandler))) http.HandleFunc("/submit", corsMiddleware(loggingMiddleware(h.SubmitHandler)))
http.HandleFunc("/status", corsMiddleware(loggingMiddleware(h.StatusHandler))) http.HandleFunc("/status", corsMiddleware(loggingMiddleware(h.StatusHandler)))
http.HandleFunc("/result", corsMiddleware(loggingMiddleware(h.ResultHandler))) http.HandleFunc("/result", corsMiddleware(loggingMiddleware(h.ResultHandler)))
http.HandleFunc("/queue-stats", corsMiddleware(loggingMiddleware(h.QueueStatsHandler)))
port := ":8080" port := ":8080"
log.Printf("Server started at %s", port) log.Printf("Server started at %s", port)

View File

@@ -7,6 +7,7 @@ type CodeSubmission struct {
ID string `json:"id"` ID string `json:"id"`
Code string `json:"code"` Code string `json:"code"`
Language string `json:"language"` Language string `json:"language"`
Input string `json:"input"` // Added input field for stdin
Status string `json:"status"` // "queued", "running", "completed", "failed" Status string `json:"status"` // "queued", "running", "completed", "failed"
QueuedAt time.Time `json:"queuedAt"` QueuedAt time.Time `json:"queuedAt"`
StartedAt time.Time `json:"startedAt,omitempty"` StartedAt time.Time `json:"startedAt,omitempty"`

BIN
backend/monaco Normal file

Binary file not shown.

View File

@@ -2,10 +2,13 @@ package service
import ( import (
"fmt" "fmt"
"io"
"log" "log"
"os" "os"
"os/exec" "os/exec"
"path/filepath" "path/filepath"
"regexp"
"strings"
"sync" "sync"
"time" "time"
@@ -61,6 +64,19 @@ func (s *ExecutionService) ExecuteCode(submission *model.CodeSubmission) {
log.Printf("[SUBMISSION-%s] Code submission queued for language: %s (Queue length: %d)", log.Printf("[SUBMISSION-%s] Code submission queued for language: %s (Queue length: %d)",
submission.ID, submission.Language, s.queue.QueueStats()["queue_length"]) submission.ID, submission.Language, s.queue.QueueStats()["queue_length"])
// Log if input is provided
if len(submission.Input) > 0 {
inputLen := len(submission.Input)
previewLen := 30
if inputLen > previewLen {
log.Printf("[INPUT-%s] Input provided (%d bytes): %s...",
submission.ID, inputLen, submission.Input[:previewLen])
} else {
log.Printf("[INPUT-%s] Input provided (%d bytes): %s",
submission.ID, inputLen, submission.Input)
}
}
job := NewCodeExecutionJob(s, submission) job := NewCodeExecutionJob(s, submission)
s.queue.Enqueue(job) s.queue.Enqueue(job)
} }
@@ -90,15 +106,323 @@ func (s *ExecutionService) executeLanguageSpecific(submission *model.CodeSubmiss
} }
} }
// GetQueueStats returns the current queue statistics // executeWithInput runs a command with a timeout and provides input
func (s *ExecutionService) GetQueueStats() map[string]int { func (s *ExecutionService) executeWithInput(cmd *exec.Cmd, input string, timeout time.Duration, submissionID string) ([]byte, error) {
stats := s.queue.QueueStats() log.Printf("[TIMEOUT-%s] Setting execution timeout: %v", submissionID, timeout)
log.Printf("[QUEUE] Stats - Jobs in queue: %d, Running jobs: %d, Max workers: %d",
stats["queue_length"], stats["running_jobs"], stats["max_workers"]) // Set up input pipe if input is provided
return stats if input != "" {
stdin, err := cmd.StdinPipe()
if err != nil {
log.Printf("[ERROR-%s] Failed to create stdin pipe: %v", submissionID, err)
return nil, err
} }
// Add a timeout function // Write input in a goroutine to avoid blocking
go func() {
defer stdin.Close()
io.WriteString(stdin, input)
}()
log.Printf("[INPUT-%s] Providing input to process", submissionID)
}
done := make(chan struct{})
var output []byte
var err error
go func() {
log.Printf("[EXEC-%s] Starting command execution: %v", submissionID, cmd.Args)
output, err = cmd.CombinedOutput()
close(done)
}()
select {
case <-time.After(timeout):
log.Printf("[TIMEOUT-%s] Execution timed out after %v seconds", submissionID, timeout.Seconds())
if err := cmd.Process.Kill(); err != nil {
log.Printf("[TIMEOUT-%s] Failed to kill process: %v", submissionID, err)
return nil, fmt.Errorf("timeout reached but failed to kill process: %v", err)
}
return nil, fmt.Errorf("execution timed out after %v seconds", timeout.Seconds())
case <-done:
if err != nil {
log.Printf("[EXEC-%s] Command execution failed: %v", submissionID, err)
} else {
log.Printf("[EXEC-%s] Command execution completed successfully", submissionID)
}
return output, err
}
}
// executePython runs Python code in a container
func (s *ExecutionService) executePython(submission *model.CodeSubmission) {
log.Printf("[PYTHON-%s] Preparing Python execution environment", submission.ID)
startTime := time.Now()
cmd := exec.Command("docker", "run", "--rm", "-i",
"--network=none", // No network access
"--memory=100m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=10000", // 10% CPU
"--ulimit", "nofile=64:64", // File descriptor limits
"python:3.9", "python", "-c", submission.Code)
log.Printf("[PYTHON-%s] Executing Python code with timeout: 10s", submission.ID)
var output []byte
var err error
if submission.Input != "" {
cmd.Stdin = strings.NewReader(submission.Input)
output, err = cmd.CombinedOutput()
} else {
output, err = s.executeWithTimeout(cmd, 10*time.Second, submission.ID)
}
elapsed := time.Since(startTime)
log.Printf("[PYTHON-%s] Python execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// extractClassName extracts the Java class name from code
func extractClassName(code string) string {
// Default class name as fallback
defaultClass := "Solution"
// Look for public class
re := regexp.MustCompile(`public\s+class\s+(\w+)`)
matches := re.FindStringSubmatch(code)
if len(matches) > 1 {
return matches[1]
}
// Look for any class if no public class
re = regexp.MustCompile(`class\s+(\w+)`)
matches = re.FindStringSubmatch(code)
if len(matches) > 1 {
return matches[1]
}
return defaultClass
}
// executeJava runs Java code in a container
func (s *ExecutionService) executeJava(submission *model.CodeSubmission) {
log.Printf("[JAVA-%s] Preparing Java execution environment", submission.ID)
startTime := time.Now()
// Extract class name from code
className := extractClassName(submission.Code)
log.Printf("[JAVA-%s] Detected class name: %s", submission.ID, className)
// Create temp directory for Java files
tempDir, err := os.MkdirTemp("", "java-execution-"+submission.ID)
if err != nil {
log.Printf("[JAVA-%s] Failed to create temp directory: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to create temp directory: " + err.Error()
return
}
defer os.RemoveAll(tempDir)
log.Printf("[JAVA-%s] Created temp directory: %s", submission.ID, tempDir)
// Write Java code to file with detected class name
javaFilePath := filepath.Join(tempDir, className+".java")
if err := os.WriteFile(javaFilePath, []byte(submission.Code), 0644); err != nil {
log.Printf("[JAVA-%s] Failed to write Java file: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to write Java file: " + err.Error()
return
}
log.Printf("[JAVA-%s] Wrote code to file: %s", submission.ID, javaFilePath)
// First compile without running
compileCmd := exec.Command("docker", "run", "--rm",
"-v", tempDir+":/code", // Mount code directory
"eclipse-temurin:11-jdk-alpine",
"javac", "/code/"+className+".java")
log.Printf("[JAVA-%s] Compiling Java code", submission.ID)
compileOutput, compileErr := compileCmd.CombinedOutput()
if compileErr != nil {
log.Printf("[JAVA-%s] Compilation failed: %v", submission.ID, compileErr)
submission.Status = "failed"
submission.Output = "Compilation error:\n" + string(compileOutput)
return
}
log.Printf("[JAVA-%s] Compilation successful", submission.ID)
// Now run the compiled class
runCmd := exec.Command("docker", "run", "--rm", "-i",
"--network=none", // No network access
"--memory=400m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=50000", // 50% CPU
"-v", tempDir+":/code", // Mount code directory
"eclipse-temurin:11-jdk-alpine",
"java", "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1",
"-Xverify:none", "-Xms64m", "-Xmx256m",
"-cp", "/code", className)
// Add input if provided
var output []byte
if submission.Input != "" {
log.Printf("[JAVA-%s] Executing Java code with input", submission.ID)
runCmd.Stdin = strings.NewReader(submission.Input)
output, err = runCmd.CombinedOutput()
} else {
log.Printf("[JAVA-%s] Executing Java code without input", submission.ID)
output, err = s.executeWithTimeout(runCmd, 15*time.Second, submission.ID)
}
elapsed := time.Since(startTime)
log.Printf("[JAVA-%s] Java execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// executeC runs C code in a container with improved file handling
func (s *ExecutionService) executeC(submission *model.CodeSubmission) {
log.Printf("[C-%s] Preparing C execution environment", submission.ID)
startTime := time.Now()
// Create unique temp directory for C files
tempDir, err := os.MkdirTemp("", "c-execution-"+submission.ID)
if err != nil {
log.Printf("[C-%s] Failed to create temp directory: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to create temp directory: " + err.Error()
return
}
defer os.RemoveAll(tempDir)
log.Printf("[C-%s] Created temp directory: %s", submission.ID, tempDir)
// Write C code to file
cFilePath := filepath.Join(tempDir, "solution.c")
if err := os.WriteFile(cFilePath, []byte(submission.Code), 0644); err != nil {
log.Printf("[C-%s] Failed to write C file: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to write C file: " + err.Error()
return
}
log.Printf("[C-%s] Wrote code to file: %s", submission.ID, cFilePath)
// Compile C code first
compileCmd := exec.Command("docker", "run", "--rm",
"-v", tempDir+":/code", // Mount code directory
"gcc:latest", "gcc", "-o", "/code/solution", "/code/solution.c")
compileOutput, compileErr := compileCmd.CombinedOutput()
if compileErr != nil {
log.Printf("[C-%s] Compilation failed: %v", submission.ID, compileErr)
submission.Status = "failed"
submission.Output = "Compilation error:\n" + string(compileOutput)
return
}
log.Printf("[C-%s] Compilation successful", submission.ID)
// Run C executable
runCmd := exec.Command("docker", "run", "--rm", "-i",
"--network=none", // No network access
"--memory=100m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=10000", // 10% CPU
"-v", tempDir+":/code", // Mount code directory
"gcc:latest", "/code/solution")
// Add input if provided
var output []byte
// Don't redeclare err here - use the existing variable
if submission.Input != "" {
log.Printf("[C-%s] Executing C code with input", submission.ID)
runCmd.Stdin = strings.NewReader(submission.Input)
output, err = runCmd.CombinedOutput() // Use the existing err variable
} else {
log.Printf("[C-%s] Executing C code without input", submission.ID)
output, err = s.executeWithTimeout(runCmd, 10*time.Second, submission.ID) // Use the existing err variable
}
elapsed := time.Since(startTime)
log.Printf("[C-%s] C execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// executeCpp runs C++ code in a container with improved file handling
func (s *ExecutionService) executeCpp(submission *model.CodeSubmission) {
log.Printf("[CPP-%s] Preparing C++ execution environment", submission.ID)
startTime := time.Now()
// Create unique temp directory for C++ files
tempDir, err := os.MkdirTemp("", "cpp-execution-"+submission.ID)
if err != nil {
log.Printf("[CPP-%s] Failed to create temp directory: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to create temp directory: " + err.Error()
return
}
defer os.RemoveAll(tempDir)
log.Printf("[CPP-%s] Created temp directory: %s", submission.ID, tempDir)
// Write C++ code to file
cppFilePath := filepath.Join(tempDir, "solution.cpp")
if err := os.WriteFile(cppFilePath, []byte(submission.Code), 0644); err != nil {
log.Printf("[CPP-%s] Failed to write C++ file: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to write C++ file: " + err.Error()
return
}
log.Printf("[CPP-%s] Wrote code to file: %s", submission.ID, cppFilePath)
// Compile C++ code first
compileCmd := exec.Command("docker", "run", "--rm",
"-v", tempDir+":/code", // Mount code directory
"gcc:latest", "g++", "-o", "/code/solution", "/code/solution.cpp")
compileOutput, compileErr := compileCmd.CombinedOutput()
if compileErr != nil {
log.Printf("[CPP-%s] Compilation failed: %v", submission.ID, compileErr)
submission.Status = "failed"
submission.Output = "Compilation error:\n" + string(compileOutput)
return
}
log.Printf("[CPP-%s] Compilation successful", submission.ID)
// Run C++ executable
runCmd := exec.Command("docker", "run", "--rm", "-i",
"--network=none", // No network access
"--memory=100m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=10000", // 10% CPU
"-v", tempDir+":/code", // Mount code directory
"gcc:latest", "/code/solution")
// Add input if provided
var output []byte
if submission.Input != "" {
log.Printf("[CPP-%s] Executing C++ code with input", submission.ID)
runCmd.Stdin = strings.NewReader(submission.Input)
output, err = runCmd.CombinedOutput()
} else {
log.Printf("[CPP-%s] Executing C++ code without input", submission.ID)
output, err = s.executeWithTimeout(runCmd, 10*time.Second, submission.ID)
}
elapsed := time.Since(startTime)
log.Printf("[CPP-%s] C++ execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// executeWithTimeout runs a command with a timeout
func (s *ExecutionService) executeWithTimeout(cmd *exec.Cmd, timeout time.Duration, submissionID string) ([]byte, error) { func (s *ExecutionService) executeWithTimeout(cmd *exec.Cmd, timeout time.Duration, submissionID string) ([]byte, error) {
log.Printf("[TIMEOUT-%s] Setting execution timeout: %v", submissionID, timeout) log.Printf("[TIMEOUT-%s] Setting execution timeout: %v", submissionID, timeout)
@@ -130,161 +454,6 @@ func (s *ExecutionService) executeWithTimeout(cmd *exec.Cmd, timeout time.Durati
} }
} }
// executePython runs Python code in a container
func (s *ExecutionService) executePython(submission *model.CodeSubmission) {
log.Printf("[PYTHON-%s] Preparing Python execution environment", submission.ID)
startTime := time.Now()
cmd := exec.Command("docker", "run", "--rm", "-i",
"--network=none", // No network access
"--memory=100m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=10000", // 10% CPU
"--ulimit", "nofile=64:64", // File descriptor limits
"python:3.9", "python", "-c", submission.Code)
log.Printf("[PYTHON-%s] Executing Python code with timeout: 10s", submission.ID)
output, err := s.executeWithTimeout(cmd, 10*time.Second, submission.ID)
elapsed := time.Since(startTime)
log.Printf("[PYTHON-%s] Python execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// executeJava runs Java code in a container
func (s *ExecutionService) executeJava(submission *model.CodeSubmission) {
log.Printf("[JAVA-%s] Preparing Java execution environment", submission.ID)
startTime := time.Now()
// Create temp directory for Java files
tempDir, err := os.MkdirTemp("", "java-execution")
if err != nil {
log.Printf("[JAVA-%s] Failed to create temp directory: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to create temp directory: " + err.Error()
return
}
defer os.RemoveAll(tempDir)
log.Printf("[JAVA-%s] Created temp directory: %s", submission.ID, tempDir)
// Write Java code to file
javaFilePath := filepath.Join(tempDir, "Main.java")
if err := os.WriteFile(javaFilePath, []byte(submission.Code), 0644); err != nil {
log.Printf("[JAVA-%s] Failed to write Java file: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to write Java file: " + err.Error()
return
}
log.Printf("[JAVA-%s] Wrote code to file: %s", submission.ID, javaFilePath)
// Run Java code in container with performance optimizations
cmd := exec.Command("docker", "run", "--rm",
"--network=none", // No network access
"--memory=400m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=50000", // 50% CPU
"-v", tempDir+":/code", // Mount code directory
"eclipse-temurin:11-jdk-alpine", // JDK image with Alpine base (smaller and faster)
"sh", "-c", "cd /code && javac Main.java && java -XX:+TieredCompilation -XX:TieredStopAtLevel=1 -Xverify:none -Xms64m -Xmx256m Main")
log.Printf("[JAVA-%s] Executing Java code with optimized settings", submission.ID)
output, err := s.executeWithTimeout(cmd, 20*time.Second, submission.ID)
elapsed := time.Since(startTime)
log.Printf("[JAVA-%s] Java execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// executeC runs C code in a container
func (s *ExecutionService) executeC(submission *model.CodeSubmission) {
log.Printf("[C-%s] Preparing C execution environment", submission.ID)
startTime := time.Now()
// Create temp directory for C files
tempDir, err := os.MkdirTemp("", "c-execution")
if err != nil {
log.Printf("[C-%s] Failed to create temp directory: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to create temp directory: " + err.Error()
return
}
defer os.RemoveAll(tempDir)
log.Printf("[C-%s] Created temp directory: %s", submission.ID, tempDir)
// Write C code to file
cFilePath := filepath.Join(tempDir, "main.c")
if err := os.WriteFile(cFilePath, []byte(submission.Code), 0644); err != nil {
log.Printf("[C-%s] Failed to write C file: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to write C file: " + err.Error()
return
}
log.Printf("[C-%s] Wrote code to file: %s", submission.ID, cFilePath)
// Run C code in container
cmd := exec.Command("docker", "run", "--rm",
"--network=none", // No network access
"--memory=100m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=10000", // 10% CPU
"-v", tempDir+":/code", // Mount code directory
"gcc:latest", "bash", "-c", "cd /code && gcc -o main main.c && ./main")
log.Printf("[C-%s] Executing C code with timeout: 10s", submission.ID)
output, err := s.executeWithTimeout(cmd, 10*time.Second, submission.ID)
elapsed := time.Since(startTime)
log.Printf("[C-%s] C execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// executeCpp runs C++ code in a container
func (s *ExecutionService) executeCpp(submission *model.CodeSubmission) {
log.Printf("[CPP-%s] Preparing C++ execution environment", submission.ID)
startTime := time.Now()
// Create temp directory for C++ files
tempDir, err := os.MkdirTemp("", "cpp-execution")
if err != nil {
log.Printf("[CPP-%s] Failed to create temp directory: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to create temp directory: " + err.Error()
return
}
defer os.RemoveAll(tempDir)
log.Printf("[CPP-%s] Created temp directory: %s", submission.ID, tempDir)
// Write C++ code to file
cppFilePath := filepath.Join(tempDir, "main.cpp")
if err := os.WriteFile(cppFilePath, []byte(submission.Code), 0644); err != nil {
log.Printf("[CPP-%s] Failed to write C++ file: %v", submission.ID, err)
submission.Status = "failed"
submission.Output = "Failed to write C++ file: " + err.Error()
return
}
log.Printf("[CPP-%s] Wrote code to file: %s", submission.ID, cppFilePath)
// Run C++ code in container
cmd := exec.Command("docker", "run", "--rm",
"--network=none", // No network access
"--memory=100m", // Memory limit
"--cpu-period=100000", // CPU quota period
"--cpu-quota=10000", // 10% CPU
"-v", tempDir+":/code", // Mount code directory
"gcc:latest", "bash", "-c", "cd /code && g++ -o main main.cpp && ./main")
log.Printf("[CPP-%s] Executing C++ code with timeout: 10s", submission.ID)
output, err := s.executeWithTimeout(cmd, 10*time.Second, submission.ID)
elapsed := time.Since(startTime)
log.Printf("[CPP-%s] C++ execution completed in %v", submission.ID, elapsed)
s.updateSubmissionResult(submission, output, err)
}
// updateSubmissionResult updates the submission with execution results // updateSubmissionResult updates the submission with execution results
func (s *ExecutionService) updateSubmissionResult(submission *model.CodeSubmission, output []byte, err error) { func (s *ExecutionService) updateSubmissionResult(submission *model.CodeSubmission, output []byte, err error) {
s.mu.Lock() s.mu.Lock()
@@ -306,3 +475,11 @@ func (s *ExecutionService) updateSubmissionResult(submission *model.CodeSubmissi
submission.ID, executionTime, totalTime, totalTime-executionTime) submission.ID, executionTime, totalTime, totalTime-executionTime)
} }
} }
// GetQueueStats returns statistics about the job queue
func (s *ExecutionService) GetQueueStats() map[string]int {
stats := s.queue.QueueStats()
log.Printf("[QUEUE] Stats - Jobs in queue: %d, Running jobs: %d, Max workers: %d",
stats["queue_length"], stats["running_jobs"], stats["max_workers"])
return stats
}

View File

@@ -1 +1 @@
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1

Binary file not shown.