extended java & isolate logging, java fix, local test fix
All checks were successful
Build and Push Docker Images / build (src/LiquidCode.Tester.Gateway/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-gateway-roman, gateway) (push) Successful in 15m53s
Build and Push Docker Images / build (src/LiquidCode.Tester.Worker/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-worker-roman, worker) (push) Successful in 6m32s
All checks were successful
Build and Push Docker Images / build (src/LiquidCode.Tester.Gateway/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-gateway-roman, gateway) (push) Successful in 15m53s
Build and Push Docker Images / build (src/LiquidCode.Tester.Worker/Dockerfile, git.nullptr.top/liquidcode/liquidcode-tester-worker-roman, worker) (push) Successful in 6m32s
This commit is contained in:
@@ -163,12 +163,16 @@ public class IsolateService
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.StdoutFile))
|
if (!string.IsNullOrEmpty(options.StdoutFile))
|
||||||
{
|
{
|
||||||
args.Add($"--stdout={MapSandboxPath(options.StdoutFile, options.BoxId)}");
|
var mappedStdout = MapSandboxPath(options.StdoutFile, options.BoxId);
|
||||||
|
_logger.LogDebug("Stdout mapping: {Original} -> {Mapped}", options.StdoutFile, mappedStdout);
|
||||||
|
args.Add($"--stdout={mappedStdout}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(options.StderrFile))
|
if (!string.IsNullOrEmpty(options.StderrFile))
|
||||||
{
|
{
|
||||||
args.Add($"--stderr={MapSandboxPath(options.StderrFile, options.BoxId)}");
|
var mappedStderr = MapSandboxPath(options.StderrFile, options.BoxId);
|
||||||
|
_logger.LogDebug("Stderr mapping: {Original} -> {Mapped}", options.StderrFile, mappedStderr);
|
||||||
|
args.Add($"--stderr={mappedStderr}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Working directory
|
// Working directory
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using LiquidCode.Tester.Worker.Services.Isolate;
|
using LiquidCode.Tester.Worker.Services.Isolate;
|
||||||
using LiquidCode.Tester.Worker.Models;
|
using LiquidCode.Tester.Worker.Models;
|
||||||
|
|
||||||
@@ -30,16 +32,18 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
|
|
||||||
public async Task<CompilationResult> CompileAsync(string sourceCode, string workingDirectory, string? version = null)
|
public async Task<CompilationResult> CompileAsync(string sourceCode, string workingDirectory, string? version = null)
|
||||||
{
|
{
|
||||||
var sourceFilePath = Path.Combine(workingDirectory, "Solution.java");
|
// Extract class name from source code
|
||||||
var classFilePath = Path.Combine(workingDirectory, "Solution.class");
|
var className = ExtractPublicClassName(sourceCode) ?? "Solution";
|
||||||
|
var sourceFilePath = Path.Combine(workingDirectory, $"{className}.java");
|
||||||
|
var classFilePath = Path.Combine(workingDirectory, $"{className}.class");
|
||||||
|
|
||||||
_logger.LogInformation("Compiling Java code with Isolate in {WorkingDirectory} with version {Version}",
|
_logger.LogInformation("Compiling Java code with Isolate in {WorkingDirectory} with version {Version}, class: {ClassName}",
|
||||||
workingDirectory, version ?? "latest");
|
workingDirectory, version ?? "latest", className);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await File.WriteAllTextAsync(sourceFilePath, sourceCode);
|
await File.WriteAllTextAsync(sourceFilePath, sourceCode);
|
||||||
return await CompileFileInIsolateAsync(sourceFilePath, classFilePath, workingDirectory, version);
|
return await CompileFileInIsolateAsync(sourceFilePath, classFilePath, workingDirectory, version, className);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -52,11 +56,22 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Extract public class name from Java source code
|
||||||
|
/// </summary>
|
||||||
|
private static string? ExtractPublicClassName(string sourceCode)
|
||||||
|
{
|
||||||
|
// Match "public class ClassName" (with optional generics, extends, implements)
|
||||||
|
var match = Regex.Match(sourceCode, @"public\s+class\s+(\w+)");
|
||||||
|
return match.Success ? match.Groups[1].Value : null;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task<CompilationResult> CompileFileInIsolateAsync(
|
private async Task<CompilationResult> CompileFileInIsolateAsync(
|
||||||
string sourceFilePath,
|
string sourceFilePath,
|
||||||
string classFilePath,
|
string classFilePath,
|
||||||
string workingDirectory,
|
string workingDirectory,
|
||||||
string? version = null)
|
string? version = null,
|
||||||
|
string className = "Solution")
|
||||||
{
|
{
|
||||||
int boxId = -1;
|
int boxId = -1;
|
||||||
|
|
||||||
@@ -87,6 +102,13 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
var stderrFilePath = Path.Combine(boxDir, "compile_stderr.txt");
|
var stderrFilePath = Path.Combine(boxDir, "compile_stderr.txt");
|
||||||
var stdoutFilePath = Path.Combine(boxDir, "compile_stdout.txt");
|
var stdoutFilePath = Path.Combine(boxDir, "compile_stdout.txt");
|
||||||
|
|
||||||
|
// Create empty files for stdout/stderr (isolate might require them to exist)
|
||||||
|
await File.WriteAllTextAsync(stdoutFilePath, string.Empty);
|
||||||
|
await File.WriteAllTextAsync(stderrFilePath, string.Empty);
|
||||||
|
|
||||||
|
_logger.LogDebug("Stdout will be written to: {StdoutPath}", stdoutFilePath);
|
||||||
|
_logger.LogDebug("Stderr will be written to: {StderrPath}", stderrFilePath);
|
||||||
|
|
||||||
var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions
|
var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions
|
||||||
{
|
{
|
||||||
BoxId = boxId,
|
BoxId = boxId,
|
||||||
@@ -103,11 +125,16 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
WorkingDirectory = "/box",
|
WorkingDirectory = "/box",
|
||||||
DirectoryBindings = new List<DirectoryBinding>
|
DirectoryBindings = new List<DirectoryBinding>
|
||||||
{
|
{
|
||||||
new DirectoryBinding { HostPath = "/usr/bin", SandboxPath = "/usr/bin", ReadOnly = true },
|
|
||||||
new DirectoryBinding { HostPath = "/usr/lib", SandboxPath = "/usr/lib", ReadOnly = true },
|
new DirectoryBinding { HostPath = "/usr/lib", SandboxPath = "/usr/lib", ReadOnly = true },
|
||||||
new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true },
|
new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true },
|
||||||
new DirectoryBinding { HostPath = "/lib64", SandboxPath = "/lib64", ReadOnly = true },
|
new DirectoryBinding { HostPath = "/lib64", SandboxPath = "/lib64", ReadOnly = true },
|
||||||
|
new DirectoryBinding { HostPath = "/usr/bin", SandboxPath = "/usr/bin", ReadOnly = true },
|
||||||
|
new DirectoryBinding { HostPath = "/bin", SandboxPath = "/bin", ReadOnly = true },
|
||||||
new DirectoryBinding { HostPath = "/etc", SandboxPath = "/etc", ReadOnly = true }
|
new DirectoryBinding { HostPath = "/etc", SandboxPath = "/etc", ReadOnly = true }
|
||||||
|
},
|
||||||
|
EnvironmentVariables = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["PATH"] = "/usr/local/bin:/usr/bin:/bin"
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -122,6 +149,14 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
compilerOutput = stdoutContent;
|
compilerOutput = stdoutContent;
|
||||||
_logger.LogDebug("Read stdout file: {Length} bytes", stdoutContent.Length);
|
_logger.LogDebug("Read stdout file: {Length} bytes", stdoutContent.Length);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Stdout file exists but is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Stdout file does not exist at {Path}", stdoutFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read stderr
|
// Read stderr
|
||||||
@@ -135,6 +170,14 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
: $"{compilerOutput}\n{stderrContent}";
|
: $"{compilerOutput}\n{stderrContent}";
|
||||||
_logger.LogDebug("Read stderr file: {Length} bytes", stderrContent.Length);
|
_logger.LogDebug("Read stderr file: {Length} bytes", stderrContent.Length);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Stderr file exists but is empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Stderr file does not exist at {Path}", stderrFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(isolateResult.ErrorOutput))
|
if (!string.IsNullOrEmpty(isolateResult.ErrorOutput))
|
||||||
@@ -169,7 +212,7 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Copy .class file back
|
// Copy .class file back
|
||||||
var boxClassPath = Path.Combine(boxDir, "Solution.class");
|
var boxClassPath = Path.Combine(boxDir, $"{className}.class");
|
||||||
if (isolateResult.ExitCode == 0 && File.Exists(boxClassPath))
|
if (isolateResult.ExitCode == 0 && File.Exists(boxClassPath))
|
||||||
{
|
{
|
||||||
Directory.CreateDirectory(Path.GetDirectoryName(classFilePath)!);
|
Directory.CreateDirectory(Path.GetDirectoryName(classFilePath)!);
|
||||||
@@ -184,8 +227,8 @@ public class JavaCompilationServiceIsolate : ICompilationService
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogWarning("Java compilation failed with exit code {ExitCode} in box {BoxId}",
|
_logger.LogWarning("Java compilation failed with exit code {ExitCode} in box {BoxId}. Compiler output: {Output}",
|
||||||
isolateResult.ExitCode, boxId);
|
isolateResult.ExitCode, boxId, compilerOutput);
|
||||||
return new CompilationResult
|
return new CompilationResult
|
||||||
{
|
{
|
||||||
Success = false,
|
Success = false,
|
||||||
|
|||||||
@@ -73,11 +73,14 @@ public class JavaExecutionServiceIsolate : IExecutionService
|
|||||||
var jvmHeapMb = memoryLimitMb;
|
var jvmHeapMb = memoryLimitMb;
|
||||||
var jvmTotalMemoryMb = memoryLimitMb + 64; // Add 64MB for JVM overhead (metaspace, code cache, etc.)
|
var jvmTotalMemoryMb = memoryLimitMb + 64; // Add 64MB for JVM overhead (metaspace, code cache, etc.)
|
||||||
|
|
||||||
|
// Extract class name from .class file path
|
||||||
|
var className = Path.GetFileNameWithoutExtension(executablePath);
|
||||||
|
|
||||||
var arguments = new List<string>
|
var arguments = new List<string>
|
||||||
{
|
{
|
||||||
$"-Xmx{jvmHeapMb}m", // Max heap size = requested memory limit
|
$"-Xmx{jvmHeapMb}m", // Max heap size = requested memory limit
|
||||||
$"-Xms{Math.Min(jvmHeapMb, 32)}m", // Initial heap size (min 32MB or requested)
|
$"-Xms{Math.Min(jvmHeapMb, 32)}m", // Initial heap size (min 32MB or requested)
|
||||||
"-cp", "/box", "Solution"
|
"-cp", "/box", className
|
||||||
};
|
};
|
||||||
|
|
||||||
var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions
|
var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions
|
||||||
|
|||||||
Reference in New Issue
Block a user