一些远程判题的BUG修复

This commit is contained in:
Himit_ZH 2021-03-26 18:47:43 +08:00
parent ebcf88c38a
commit 245f6c668a
26 changed files with 82 additions and 62 deletions

View File

@ -30,6 +30,7 @@ public class RemoteJudgeDispatcher {
task.set("isContest", isContest); task.set("isContest", isContest);
task.set("tryAgainNum", tryAgainNum); task.set("tryAgainNum", tryAgainNum);
try { try {
// 对应列表右边取出账号
String account = (String) redisUtils.lrPop(Constants.Judge.getListNameByOJName(remoteJudge.split("-")[0])); String account = (String) redisUtils.lrPop(Constants.Judge.getListNameByOJName(remoteJudge.split("-")[0]));
if (account != null) { if (account != null) {
JSONObject accountJson = JSONUtil.parseObj(account); JSONObject accountJson = JSONUtil.parseObj(account);

View File

@ -14,6 +14,8 @@ import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.ToJudge; import top.hcode.hoj.pojo.entity.ToJudge;
import top.hcode.hoj.service.ToJudgeService; import top.hcode.hoj.service.ToJudgeService;
import top.hcode.hoj.service.impl.JudgeServiceImpl; import top.hcode.hoj.service.impl.JudgeServiceImpl;
import top.hcode.hoj.utils.Constants;
import top.hcode.hoj.utils.RedisUtils;
@Component @Component
public class RemoteJudgeReceiver implements MessageListener { public class RemoteJudgeReceiver implements MessageListener {
@ -27,6 +29,9 @@ public class RemoteJudgeReceiver implements MessageListener {
@Autowired @Autowired
private JudgeServiceImpl judgeService; private JudgeServiceImpl judgeService;
@Autowired
private RedisUtils redisUtils;
@Override @Override
public void onMessage(Message message, byte[] bytes) { public void onMessage(Message message, byte[] bytes) {
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
@ -45,6 +50,8 @@ public class RemoteJudgeReceiver implements MessageListener {
String password = task.getStr("password"); String password = task.getStr("password");
Integer tryAgainNum = task.getInt("tryAgainNum"); Integer tryAgainNum = task.getInt("tryAgainNum");
System.out.println(username);
System.out.println(password);
if (username == null || password == null) { if (username == null || password == null) {
remoteJudgeDispatcher.sendTask(submitId, pid, token, remoteJudge, isContest, tryAgainNum); remoteJudgeDispatcher.sendTask(submitId, pid, token, remoteJudge, isContest, tryAgainNum);
@ -52,6 +59,7 @@ public class RemoteJudgeReceiver implements MessageListener {
} }
Judge judge = judgeService.getById(submitId); Judge judge = judgeService.getById(submitId);
// 调用判题服务 // 调用判题服务
toJudgeService.remoteJudge(new ToJudge() toJudgeService.remoteJudge(new ToJudge()
.setJudge(judge) .setJudge(judge)

View File

@ -26,8 +26,8 @@ spring:
timeout: 60000 timeout: 60000
jedis: jedis:
pool: pool:
min-idle: 10 #连接池中的最小空闲连接 min-idle: 50 #连接池中的最小空闲连接
max-idle: 100 #连接池中的最大空闲连接 max-idle: 200 #连接池中的最大空闲连接
max-active: 500 #连接池最大连接数(使用负值表示没有限制) max-active: 500 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
datasource: datasource:

View File

@ -26,8 +26,8 @@ spring:
timeout: 60000 timeout: 60000
jedis: jedis:
pool: pool:
min-idle: 10 #连接池中的最小空闲连接 min-idle: 50 #连接池中的最小空闲连接
max-idle: 100 #连接池中的最大空闲连接 max-idle: 200 #连接池中的最大空闲连接
max-active: 500 #连接池最大连接数(使用负值表示没有限制) max-active: 500 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)
datasource: datasource:

View File

@ -119,6 +119,11 @@ public class JudgeController {
if (!toJudge.getToken().equals(judgeToken)) { if (!toJudge.getToken().equals(judgeToken)) {
return CommonResult.errorResponse("对不起!您使用的判题服务调用凭证不正确!访问受限!", CommonResult.STATUS_ACCESS_DENIED); return CommonResult.errorResponse("对不起!您使用的判题服务调用凭证不正确!访问受限!", CommonResult.STATUS_ACCESS_DENIED);
} }
if (toJudge.getJudge() == null) {
return CommonResult.errorResponse("请求参数不能为空!");
}
Long submitId = toJudge.getJudge().getSubmitId(); Long submitId = toJudge.getJudge().getSubmitId();
String uid = toJudge.getJudge().getUid(); String uid = toJudge.getJudge().getUid();
Long cid = toJudge.getJudge().getCid(); Long cid = toJudge.getJudge().getCid();
@ -136,13 +141,11 @@ public class JudgeController {
remoteJudgeSubmitDispatcher.sendTask(username, password, remoteJudge, remotePid, submitId, uid, cid, pid, language, userCode); remoteJudgeSubmitDispatcher.sendTask(username, password, remoteJudge, remotePid, submitId, uid, cid, pid, language, userCode);
return CommonResult.successResponse(null, "提交成功"); return CommonResult.successResponse(null, "提交成功");
} catch (Exception e) { } catch (Exception e) {
// 将使用的账号放回对应列表 // 将使用的账号放回对应列表
JSONObject account = new JSONObject(); JSONObject account = new JSONObject();
account.set("username", username); account.set("username", username);
account.set("password", password); account.set("password", password);
redisUtils.llPush(Constants.RemoteJudge.getListNameByOJName(remoteJudge), JSONUtil.toJsonStr(account)); redisUtils.llPush(Constants.RemoteJudge.getListNameByOJName(remoteJudge), JSONUtil.toJsonStr(account));
Judge judge = new Judge(); Judge judge = new Judge();
judge.setSubmitId(submitId) judge.setSubmitId(submitId)
.setStatus(Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()) .setStatus(Constants.Judge.STATUS_SYSTEM_ERROR.getStatus())

View File

@ -69,9 +69,10 @@ public class RemoteJudgeResultReceiver implements MessageListener {
judge.setSubmitId(submitId); judge.setSubmitId(submitId);
Integer status = (Integer) result.getOrDefault("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()); Integer status = (Integer) result.getOrDefault("status", Constants.Judge.STATUS_SYSTEM_ERROR.getStatus());
// TODO 如果结果没出来重新放入队列并更新状态为Waiting // TODO 如果结果没出来重新放入队列并更新状态为Waiting
if (status.equals(Constants.Judge.STATUS_PENDING.getStatus())) { if (status.intValue() == Constants.Judge.STATUS_PENDING.getStatus() ||
status.intValue() == Constants.Judge.STATUS_JUDGING.getStatus()) {
try { try {
TimeUnit.SECONDS.sleep(1); TimeUnit.SECONDS.sleep(2);
remoteJudgeResultDispatcher.sendTask(remoteJudge, username, submitId, uid, cid, pid, resultSubmitId, token, cookies); remoteJudgeResultDispatcher.sendTask(remoteJudge, username, submitId, uid, cid, pid, resultSubmitId, token, cookies);
} catch (Exception e) { } catch (Exception e) {
log.error("重新查询结果任务出错------{}", e.getMessage()); log.error("重新查询结果任务出错------{}", e.getMessage());
@ -93,7 +94,7 @@ public class RemoteJudgeResultReceiver implements MessageListener {
} else if (status.intValue() == Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()) { } else if (status.intValue() == Constants.Judge.STATUS_SYSTEM_ERROR.getStatus()) {
judge.setErrorMessage("There is something wrong with the " + remoteJudge + ", please try again later"); judge.setErrorMessage("There is something wrong with the " + remoteJudge + ", please try again later");
} }
// 写回数据库 // 写回数据库
judgeService.updateById(judge); judgeService.updateById(judge);
/** /**
@ -103,7 +104,7 @@ public class RemoteJudgeResultReceiver implements MessageListener {
judgeService.updateOtherTable(submitId, status, cid, uid, pid, null); judgeService.updateOtherTable(submitId, status, cid, uid, pid, null);
} catch (Exception e) { } catch (Exception e) {
log.error("获取结果出错------------>{}", e.getMessage()); log.error("获取结果出错------------>{}", e.getLocalizedMessage());
// 更新此次提交状态为提交失败 // 更新此次提交状态为提交失败
UpdateWrapper<Judge> judgeUpdateWrapper = new UpdateWrapper<>(); UpdateWrapper<Judge> judgeUpdateWrapper = new UpdateWrapper<>();
judgeUpdateWrapper.set("status", Constants.Judge.STATUS_SUBMITTED_FAILED.getStatus()) judgeUpdateWrapper.set("status", Constants.Judge.STATUS_SUBMITTED_FAILED.getStatus())

View File

@ -30,7 +30,7 @@ public class RemoteJudgeSubmitDispatcher {
task.set("language", language); task.set("language", language);
task.set("username", username); task.set("username", username);
task.set("password", password); task.set("password", password);
redisUtils.sendMessage(Constants.RemoteJudge.JUDGE_SUBMIT_HANDLER.getName(), "New Problem Added");
redisUtils.lrPush(Constants.RemoteJudge.JUDGE_WAITING_SUBMIT_QUEUE.getName(), JSONUtil.toJsonStr(task)); redisUtils.lrPush(Constants.RemoteJudge.JUDGE_WAITING_SUBMIT_QUEUE.getName(), JSONUtil.toJsonStr(task));
redisUtils.sendMessage(Constants.RemoteJudge.JUDGE_SUBMIT_HANDLER.getName(), "New Problem Added");
} }
} }

View File

@ -56,21 +56,21 @@ public class RemoteJudgeSubmitReceiver implements MessageListener {
// 获取不到对应的题库或者题库写错了 // 获取不到对应的题库或者题库写错了
if (remoteJudgeStrategy == null) { if (remoteJudgeStrategy == null) {
log.error("暂不支持该{}题库---------------->请求失败", remoteJudge); log.error("暂不支持该{}题库---------------->请求失败", remoteJudge);
return;
} }
Map<String, Object> submitResult = null; Map<String, Object> submitResult = null;
try { try {
submitResult = remoteJudgeStrategy.submit(username, password, remotePid, language, userCode); submitResult = remoteJudgeStrategy.submit(username, password, remotePid, language, userCode);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
}finally {
// 将使用的账号放回对应列表
JSONObject account = new JSONObject();
account.set("username", username);
account.set("password", password);
redisUtils.llPush(Constants.RemoteJudge.getListNameByOJName(remoteJudge), JSONUtil.toJsonStr(account));
} }
// 提交成功与失败都要把账号放回list
JSONObject account = new JSONObject();
account.set("username", username);
account.set("password", password);
redisUtils.llPush(Constants.RemoteJudge.getListNameByOJName(remoteJudge), JSONUtil.toJsonStr(account));
// TODO 提交失败 前端手动按按钮再次提交 修改状态 STATUS_SUBMITTED_FAILED // TODO 提交失败 前端手动按按钮再次提交 修改状态 STATUS_SUBMITTED_FAILED
if (submitResult == null || (Long) submitResult.getOrDefault("runId", -1L) == -1L) { if (submitResult == null || (Long) submitResult.getOrDefault("runId", -1L) == -1L) {
// 更新此次提交状态为提交失败 // 更新此次提交状态为提交失败
@ -82,13 +82,12 @@ public class RemoteJudgeSubmitReceiver implements MessageListener {
return; return;
} }
// 提交成功顺便更新状态为-->STATUS_JUDGING 判题中... // 提交成功顺便更新状态为-->STATUS_JUDGING 判题中...
judgeService.updateById(new Judge().setSubmitId(submitId).setStatus(Constants.Judge.STATUS_JUDGING.getStatus())); judgeService.updateById(new Judge().setSubmitId(submitId).setStatus(Constants.Judge.STATUS_JUDGING.getStatus()));
try { try {
remoteJudgeResultDispatcher.sendTask(remoteJudge, username, submitId, uid, cid, pid, remoteJudgeResultDispatcher.sendTask(remoteJudge, username, submitId, uid, cid, pid,
(Long) submitResult.get("runId"),(String) submitResult.get("token"), (Long) submitResult.get("runId"), (String) submitResult.get("token"),
(HashMap<String, String>)submitResult.get("cookies")); (HashMap<String, String>) submitResult.get("cookies"));
} catch (Exception e) { } catch (Exception e) {
log.error("调用redis消息发布异常,此次远程查询结果任务判为系统错误--------------->{}", e.getMessage()); log.error("调用redis消息发布异常,此次远程查询结果任务判为系统错误--------------->{}", e.getMessage());
} }

View File

@ -3,6 +3,7 @@ package top.hcode.hoj.remoteJudge.task.Impl;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.text.UnicodeUtil; import cn.hutool.core.text.UnicodeUtil;
import cn.hutool.core.util.ReUtil; import cn.hutool.core.util.ReUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject; import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil; import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -122,44 +123,49 @@ public class CodeForcesJudge implements RemoteJudgeStrategy {
@Override @Override
public Map<String, Object> result(Long submitId, String username, String token, HashMap<String, String> cookies) throws Exception { public Map<String, Object> result(Long submitId, String username, String token, HashMap<String, String> cookies) throws Exception {
String url = HOST + String.format(SUBMISSION_RESULT_URL, username); String url = HOST + String.format(SUBMISSION_RESULT_URL, username);
Connection connection = JsoupUtils.getConnectionFromUrl(url, headers, null); Connection connection = JsoupUtils.getConnectionFromUrl(url, headers, cookies);
connection.ignoreContentType(true); connection.ignoreContentType(true);
Connection.Response response = JsoupUtils.getResponse(connection, null); Connection.Response response = JsoupUtils.getResponse(connection, null);
Map<String, Object> json = (Map<String, Object>) JSONUtil.parseObj(response.body());
List<Map<String, Object>> results = (List<Map<String, Object>>) json.get("result"); JSONObject jsonObject = JSONUtil.parseObj(response.body());
for (Map<String, Object> result : results) {
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("status", Constants.Judge.STATUS_JUDGING.getStatus());
JSONArray results = (JSONArray) jsonObject.get("result");
for (Object tmp : results) {
JSONObject result = (JSONObject) tmp;
long runId = Long.parseLong(result.get("id").toString()); long runId = Long.parseLong(result.get("id").toString());
if (runId != submitId) { if (runId == submitId) {
continue; String verdict = (String) result.get("verdict");
Constants.Judge statusType = statusMap.get(verdict);
if (statusType == Constants.Judge.STATUS_JUDGING) {
return MapUtil.builder(new HashMap<String, Object>())
.put("status", statusType.getStatus()).build();
}
resultMap.put("time", result.get("timeConsumedMillis"));
resultMap.put("memory", result.get("memoryConsumedBytes"));
Constants.Judge resultStatus = statusMap.get(verdict);
if (resultStatus == Constants.Judge.STATUS_COMPILE_ERROR) {
Connection CEInfoConnection = JsoupUtils.getConnectionFromUrl(HOST + CE_INFO_URL, headers, cookies);
CEInfoConnection.ignoreContentType(true);
Connection.Response CEInfoResponse = JsoupUtils.postResponse(CEInfoConnection, MapUtil
.builder(new HashMap<String, String>())
.put("csrf_token", token)
.put("submissionId", submitId.toString()).map());
resultMap.put("CEInfo", UnicodeUtil.toString(CEInfoResponse.body()).replaceAll("(\\\\r)?\\\\n", "\n")
.replaceAll("\\\\\\\\", "\\\\"));
}
resultMap.put("status", resultStatus.getStatus());
return resultMap;
} }
String verdict = (String) result.get("verdict");
Constants.Judge statusType = statusMap.get(verdict);
if (statusType == Constants.Judge.STATUS_JUDGING) {
return MapUtil.builder(new HashMap<String, Object>())
.put("status", statusType.getStatus()).build();
}
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("time", result.get("timeConsumedMillis"));
resultMap.put("memory", result.get("memoryConsumedBytes"));
Constants.Judge resultStatus = statusMap.get(verdict);
if (resultStatus == Constants.Judge.STATUS_COMPILE_ERROR) {
Connection CEInfoConnection = JsoupUtils.getConnectionFromUrl(HOST + CE_INFO_URL, headers, cookies);
CEInfoConnection.ignoreContentType(true);
Connection.Response CEInfoResponse = JsoupUtils.postResponse(CEInfoConnection, MapUtil
.builder(new HashMap<String, String>())
.put("csrf_token", token)
.put("submissionId", submitId.toString()).map());
resultMap.put("CEInfo", UnicodeUtil.toString(CEInfoResponse.body()).replaceAll("(\\\\r)?\\\\n", "\n")
.replaceAll("\\\\\\\\", "\\\\"));
}
resultMap.put("status", resultStatus.getStatus());
return resultMap;
} }
return null; return resultMap;
} }
@Override @Override

View File

@ -43,9 +43,10 @@ public class HduJudge implements RemoteJudgeStrategy {
.builder(new HashMap<String, String>()) .builder(new HashMap<String, String>())
.put("check", "0") .put("check", "0")
.put("language", getLanguage(language)) .put("language", getLanguage(language))
.put("problemid", String.valueOf(problemId)) .put("problemid", problemId)
.put("usercode", userCode) .put("usercode", userCode)
.map()); .map());
if (response.statusCode() != 200) { if (response.statusCode() != 200) {
log.error("进行题目提交时发生错误:提交题目失败," + HduJudge.class.getName() + ",题号:" + problemId); log.error("进行题目提交时发生错误:提交题目失败," + HduJudge.class.getName() + ",题号:" + problemId);
return null; return null;

View File

@ -4,6 +4,7 @@ package top.hcode.hoj.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import top.hcode.hoj.common.exception.CompileError; import top.hcode.hoj.common.exception.CompileError;
import top.hcode.hoj.common.exception.SystemError; import top.hcode.hoj.common.exception.SystemError;

View File

@ -34,9 +34,9 @@ spring:
timeout: 100000 timeout: 100000
jedis: jedis:
pool: pool:
min-idle: 10 #连接池中的最小空闲连接 min-idle: 20 #连接池中的最小空闲连接
max-idle: 50 #连接池中的最大空闲连接 max-idle: 100 #连接池中的最大空闲连接
max-active: 100 #连接池最大连接数(使用负值表示没有限制) max-active: 200 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)

View File

@ -34,9 +34,9 @@ spring:
timeout: 100000 timeout: 100000
jedis: jedis:
pool: pool:
min-idle: 10 #连接池中的最小空闲连接 min-idle: 20 #连接池中的最小空闲连接
max-idle: 50 #连接池中的最大空闲连接 max-idle: 100 #连接池中的最大空闲连接
max-active: 100 #连接池最大连接数(使用负值表示没有限制) max-active: 200 #连接池最大连接数(使用负值表示没有限制)
max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制) max-wait: -1 #连接池最大阻塞等待时间(使用负值表示没有限制)

View File

@ -169,7 +169,7 @@
</template> </template>
</vxe-table-column> </vxe-table-column>
<vxe-table-column field="language" title="Language" min-width="100"> <vxe-table-column field="language" title="Language" min-width="130">
<template v-slot="{ row }"> <template v-slot="{ row }">
<span <span
v-if="!row.share && row.uid != userInfo.uid && !isAdminRole" v-if="!row.share && row.uid != userInfo.uid && !isAdminRole"