Skip to content

Commit

Permalink
Add judge server singleton
Browse files Browse the repository at this point in the history
  • Loading branch information
slhmy committed Oct 15, 2023
1 parent c2b20a2 commit 5a07971
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 22 deletions.
2 changes: 1 addition & 1 deletion dev-problem-package/hello-world/.timelimit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1
2
42 changes: 23 additions & 19 deletions judge-server/src/service/judge.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::{fs, path::PathBuf};

use crate::error::ServiceError;
use crate::{error::ServiceError, service::state};
use actix_web::{post, web, HttpResponse};

use judge_core::{
Expand Down Expand Up @@ -28,12 +28,12 @@ pub fn route(cfg: &mut web::ServiceConfig) {
// TODO: Remove the first `_` when the segment is actually used
#[derive(Debug, ToSchema, Deserialize)]
pub struct RunJudgeBody {
src: String,
src_language: Language
code: String,
language: Language,
}

#[utoipa::path(
context_path = "/api/v1/judge",
context_path = "/api/v1/judge",
request_body(content = RunJudgeBody, content_type = "application/json", description = "The info a judge task should refer to"),
responses(
(status = 200, description = "Judge run successfully")
Expand All @@ -45,42 +45,45 @@ pub async fn run_judge(
body: web::Json<RunJudgeBody>,
problem_package_dir: web::Data<PathBuf>,
) -> Result<HttpResponse, ServiceError> {
state::set_busy().map_err(|e| {
println!("Failed to set busy: {:?}", e);
ServiceError::InternalError(anyhow::anyhow!("Judge server is busy"))
})?;

let package_slug = path.into_inner();
log::debug!("receive body: {:?}", body);

let uuid = uuid::Uuid::new_v4();
let runtime_path = PathBuf::from("/tmp").join(uuid.to_string());
let src_file_name = format!("src.{}", body.src_language.get_extension());
println!("runtime_path: {:?}", runtime_path);
let src_file_name = format!("src.{}", body.language.get_extension());
log::debug!("runtime_path: {:?}", runtime_path);
fs::create_dir_all(runtime_path.clone()).map_err(|e| {
println!("Failed to create runtime dir: {:?}", e);
log::debug!("Failed to create runtime dir: {:?}", e);
ServiceError::InternalError(anyhow::anyhow!("Failed to create runtime dir"))
})?;
fs::write(runtime_path.clone().join(&src_file_name), body.src.clone()).map_err(
|e| {
println!("Failed to write src file: {:?}", e);
ServiceError::InternalError(anyhow::anyhow!("Failed to write src file"))
},
)?;
fs::write(runtime_path.clone().join(&src_file_name), body.code.clone()).map_err(|e| {
log::debug!("Failed to write src file: {:?}", e);
ServiceError::InternalError(anyhow::anyhow!("Failed to write src file"))
})?;

let handle: JoinHandle<Result<Vec<JudgeResultInfo>, JudgeCoreError>> =
tokio::spawn(async move {
let new_builder_result = JudgeBuilder::new(JudgeBuilderInput {
package_type: PackageType::ICPC,
package_path: problem_package_dir.join(package_slug.clone()),
runtime_path: runtime_path.clone(),
src_language: body.src_language,
src_language: body.language,
src_path: runtime_path.clone().join(&src_file_name),
});
if new_builder_result.is_err() {
println!(
log::debug!(
"Failed to new builder result: {:?}",
new_builder_result.err()
);
return Ok(vec![]);
}
let builder = new_builder_result?;
println!("Builder created: {:?}", builder);
log::debug!("Builder created: {:?}", builder);
let mut results: Vec<JudgeResultInfo> = vec![];
for idx in 0..builder.testdata_configs.len() {
let judge_config = JudgeConfig {
Expand All @@ -90,18 +93,19 @@ pub async fn run_judge(
runtime: builder.runtime_config.clone(),
};
let result = judge::common::run_judge(&judge_config)?;
println!("Judge result: {:?}", result);
log::debug!("Judge result: {:?}", result);
results.push(result);
}

println!("BatchJudge finished");
state::set_idle();
log::debug!("Judge finished");
Ok(results)
});

match handle.await.unwrap() {
Ok(results) => Ok(HttpResponse::Ok().json(results)),
Err(e) => {
println!("Failed to await handle: {:?}", e);
log::info!("Failed to await handle: {:?}", e);
Err(ServiceError::InternalError(anyhow::anyhow!("Judge failed")))
}
}
Expand Down
1 change: 1 addition & 0 deletions judge-server/src/service/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod greet;
mod judge;
mod state;

use actix_web::web;
use utoipa::OpenApi;
Expand Down
32 changes: 32 additions & 0 deletions judge-server/src/service/state.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use std::sync::RwLock;

use lazy_static::lazy_static;

#[derive(Clone, Debug, PartialEq)]
pub enum State {
Idle,
Busy,
}

lazy_static! {
pub static ref STATE: RwLock<State> = RwLock::new(State::Idle);
}

pub fn set_busy() -> anyhow::Result<()> {
log::info!("Trying to set busy");
let mut state = STATE
.try_write()
.map_err(|e| anyhow::anyhow!("Failed to lock state: {:?}", e))?;
log::info!("State: {:?}", *state);
if *state == State::Busy {
anyhow::bail!("Judge server is busy")
}
*state = State::Busy;

Ok(())
}

pub fn set_idle() {
let mut state = STATE.write().unwrap();
*state = State::Idle;
}
33 changes: 31 additions & 2 deletions postman/Judge Server.postman_collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,42 @@
},
"item": [
{
"name": "localhost:8000/api/v1/judge/hello-world",
"name": "v1/judge/hello-world",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"src\": \"#include <iostream>\\n\\nusing namespace std;\\n\\nint main() {\\n string s;\\n cin >> s;\\n cout << \\\"Hello! \\\" << s << endl;\\n}\\n\",\r\n \"src_language\": \"Cpp\"\r\n}",
"raw": "{\r\n \"code\": \"#include <iostream>\\n\\nusing namespace std;\\n\\nint main() {\\n string s;\\n cin >> s;\\n cout << \\\"Hello! \\\" << s << endl;\\n}\\n\",\r\n \"language\": \"Cpp\"\r\n}",
"options": {
"raw": {
"language": "json"
}
}
},
"url": {
"raw": "{{Judger Host}}/api/v1/judge/hello-world",
"host": [
"{{Judger Host}}"
],
"path": [
"api",
"v1",
"judge",
"hello-world"
]
}
},
"response": []
},
{
"name": "v1/judge/hello-world TLE",
"request": {
"method": "POST",
"header": [],
"body": {
"mode": "raw",
"raw": "{\r\n \"code\": \"#include <time.h>\\r\\n#include <stdio.h>\\r\\n\\r\\nint main() {\\r\\n clock_t start, step;\\r\\n start = clock();\\r\\n step = clock();\\r\\n while (true) {\\r\\n if (clock() - step > 1000000) {\\r\\n printf(\\\"%lds has passed..\\\\n\\\", (clock() - start) \\/ 1000000);\\r\\n step = clock();\\r\\n }\\r\\n }\\r\\n}\\r\\n\",\r\n \"language\": \"Cpp\"\r\n}",
"options": {
"raw": {
"language": "json"
Expand Down

0 comments on commit 5a07971

Please sign in to comment.