This commit is contained in:
Himit_ZH 2021-05-24 21:48:48 +08:00
parent a518fea2ed
commit 380e385440
73 changed files with 285 additions and 182 deletions

View File

@ -63,6 +63,7 @@ Password: 开启SMTP服务后生成的随机授权码
| 2021-05-12 | 添加评论及回复删除,讨论举报,调整显示时间。 | Himit_ZH |
| 2021-05-16 | 完善权限控制,讨论管理员管理,讨论删除与编辑更新。 | Himit_ZH |
| 2021-05-22 | 更新docker-compose一键部署修正部分bug | Himit_ZH |
| 2021-05-24 | 判题调度乐观锁改为悲观锁 | Himit_ZH |

View File

@ -23,3 +23,4 @@ pnpm-debug.log*
*.njsproj
*.sln
*.sw?

View File

@ -6,6 +6,7 @@ import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @Author: Himit_ZH
@ -16,6 +17,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@EnableDiscoveryClient // 开启注册发现
@SpringBootApplication
@EnableAsync(proxyTargetClass=true) //开启异步注解
@EnableTransactionManagement
public class DataBackupApplication {
public static void main(String[] args) {
SpringApplication.run(DataBackupApplication.class,args);

View File

@ -1,29 +1,34 @@
package top.hcode.hoj.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @Author: Himit_ZH
* @Date: 2020/11/6 23:36
* @Description:
* @Description: 通用异步线程池
*/
@Configuration
@Slf4j(topic = "hoj")
public class AsyncTaskConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
// 线程池维护线程的最少数量
taskExecutor.setCorePoolSize(20);
taskExecutor.setCorePoolSize(10);
// 线程池维护线程的最大数量
taskExecutor.setMaxPoolSize(100);
// 缓存队列
taskExecutor.setQueueCapacity(200);
//活跃时间
taskExecutor.setKeepAliveSeconds(10);
// 对拒绝task的处理策略
//(1) 默认的ThreadPoolExecutor.AbortPolicy 处理程序遭到拒绝将抛出运行时RejectedExecutionException;
//(2) ThreadPoolExecutor.CallerRunsPolicy 线程调用运行该任务的 execute 本身此策略提供简单的反馈控制机制能够减缓新任务的提交速度
@ -31,7 +36,7 @@ public class AsyncTaskConfig implements AsyncConfigurer {
//(4) ThreadPoolExecutor.DiscardOldestPolicy 如果执行程序尚未关闭则位于工作队列头部的任务将被删除然后重试执行程序如果再次失败则重复此过程
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 线程名前缀,方便排查问题
taskExecutor.setThreadNamePrefix("order-send-thread-");
taskExecutor.setThreadNamePrefix("CommonThread-");
// 注意一定要初始化
taskExecutor.initialize();
@ -39,8 +44,19 @@ public class AsyncTaskConfig implements AsyncConfigurer {
}
/**
* 异步任务中异常处理
* @return
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) {
log.error("==========================" + arg0.getMessage() + "=======================", arg0);
log.error("exception method:" + arg1.getName());
}
};
}
}

View File

@ -0,0 +1,39 @@
package top.hcode.hoj.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @Author: Himit_ZH
* @Date: 2021/5/24 16:54
* @Description: 专用于判题的异步线程池
*/
@Configuration
@EnableAsync
public class JudgeAsyncTaskConfig {
@Bean
public Executor judgeTaskAsyncPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(2);
//最大线程数
executor.setMaxPoolSize(10);
//队列容量
executor.setQueueCapacity(300);
//活跃时间
executor.setKeepAliveSeconds(10);
//线程名字前缀
executor.setThreadNamePrefix("JudgeExecutor-");
// setRejectedExecutionHandler当pool已经达到max size的时候如何处理新任务
// CallerRunsPolicy不在新线程中执行任务而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

View File

@ -107,9 +107,6 @@ public class StartupRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
if (openRemoteJudge.equals("true")) {
addRemoteJudgeAccountToRedis();
}
// 动态修改nacos上的配置文件
if (judgeToken.equals("default")) {
configVo.setJudgeToken(IdUtil.fastSimpleUUID());
@ -147,6 +144,10 @@ public class StartupRunner implements CommandLineRunner {
configVo.setCfUsernameList(cfUsernameList);
configVo.setCfPasswordList(cfPasswordList);
configService.sendNewConfigToNacos();
if (openRemoteJudge.equals("true")) {
addRemoteJudgeAccountToRedis();
}
}
/**

View File

@ -14,7 +14,7 @@ import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import top.hcode.hoj.common.result.CommonResult;
import top.hcode.hoj.crawler.problem.ProblemStrategy;
import top.hcode.hoj.judge.JudgeServerUtils;
import top.hcode.hoj.judge.Dispatcher;
import top.hcode.hoj.pojo.dto.ProblemDto;
import top.hcode.hoj.pojo.entity.*;
import top.hcode.hoj.pojo.vo.UserRolesVo;
@ -43,7 +43,7 @@ public class AdminProblemController {
private ProblemCaseServiceImpl problemCaseService;
@Autowired
private JudgeServerUtils judgeServerUtils;
private Dispatcher dispatcher;
@Value("${hoj.judge.token}")
private String judgeToken;
@ -180,7 +180,7 @@ public class AdminProblemController {
}
compileSpj.setToken(judgeToken);
return judgeServerUtils.dispatcher("compile", "/compile-spj", compileSpj);
return dispatcher.dispatcher("compile", "/compile-spj", compileSpj);
}
@GetMapping("/import-remote-oj-problem")

View File

@ -5,7 +5,9 @@ import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import top.hcode.hoj.pojo.entity.JudgeServer;
@Mapper
@Repository
public interface JudgeServerMapper extends BaseMapper<JudgeServer> {
}

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.AuthMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.ContestExplanationMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.ContestRegisterMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.ContestScoreMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.JudgeCaseMapper">
</mapper>

View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.LanguageMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.RoleMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.SessionMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.TagMapper">
</mapper>

View File

@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="top.hcode.hoj.dao.UserAcproblemMapper">
</mapper>

View File

@ -0,0 +1,99 @@
package top.hcode.hoj.judge;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import top.hcode.hoj.pojo.entity.JudgeServer;
import top.hcode.hoj.service.impl.JudgeServerServiceImpl;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/5/24 17:30
* @Description: 筛选可用判题机
*/
@Component
@Slf4j(topic = "hoj")
public class ChooseServer {
@Autowired
private NacosDiscoveryProperties discoveryProperties;
@Value("${service-url.name}")
private String JudgeServiceName;
@Autowired
private JudgeServerServiceImpl judgeServerService;
/**
* @param
* @MethodName chooseServer
* @Description 选择可以用调用判题的判题服务器
* @Return
* @Since 2021/4/15
*/
@Transactional
public JudgeServer choose(Boolean isRemote) {
// 获取该微服务的所有健康实例
List<Instance> instances = getInstances(JudgeServiceName);
if (instances.size() <= 0) {
return null;
}
List<String> keyList = new ArrayList<>();
// 获取当前健康实例取出ip和port拼接
for (Instance instance : instances) {
keyList.add(instance.getIp() + ":" + instance.getPort());
}
// 过滤出小于或等于规定最大并发判题任务数的服务实例且健康的判题机
QueryWrapper<JudgeServer> judgeServerQueryWrapper = new QueryWrapper<>();
judgeServerQueryWrapper
.in("url", keyList)
.eq("is_remote", isRemote)
.orderByAsc("task_number")
.last("for update"); // 开启悲观锁
List<JudgeServer> judgeServerList = judgeServerService.list(judgeServerQueryWrapper);
// 获取可用判题机
for (JudgeServer judgeServer : judgeServerList) {
if (judgeServer.getTaskNumber() < judgeServer.getMaxTaskNumber()) {
judgeServer.setTaskNumber(judgeServer.getTaskNumber() + 1);
boolean isOk = judgeServerService.updateById(judgeServer);
if (isOk) {
return judgeServer;
}
}
}
return null;
}
/**
* @param serviceId
* @MethodName getInstances
* @Description 根据服务id获取对应的健康实例列表
* @Return
* @Since 2021/4/15
*/
private List<Instance> getInstances(String serviceId) {
// 获取服务发现的相关API
NamingService namingService = discoveryProperties.namingServiceInstance();
try {
// 获取该微服务的所有健康实例
return namingService.selectInstances(serviceId, true);
} catch (NacosException e) {
log.error("获取微服务健康实例发生异常--------->{}", e);
return Collections.emptyList();
}
}
}

View File

@ -1,15 +1,9 @@
package top.hcode.hoj.judge;
import com.alibaba.cloud.nacos.NacosDiscoveryProperties;
import com.alibaba.cloud.nacos.ribbon.NacosServer;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
@ -21,13 +15,9 @@ import top.hcode.hoj.service.impl.JudgeServiceImpl;
import top.hcode.hoj.service.impl.RemoteJudgeAccountServiceImpl;
import top.hcode.hoj.utils.Constants;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@ -38,13 +28,7 @@ import java.util.concurrent.atomic.AtomicInteger;
*/
@Component
@Slf4j(topic = "hoj")
public class JudgeServerUtils {
@Autowired
private NacosDiscoveryProperties discoveryProperties;
@Value("${service-url.name}")
private String JudgeServiceName;
public class Dispatcher {
@Autowired
private RestTemplate restTemplate;
@ -55,6 +39,9 @@ public class JudgeServerUtils {
@Autowired
private JudgeServiceImpl judgeService;
@Autowired
private ChooseServer chooseServer;
@Autowired
private RemoteJudgeAccountServiceImpl remoteJudgeAccountService;
@ -73,7 +60,7 @@ public class JudgeServerUtils {
return null;
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public void toJudge(String path, ToJudge data, Long submitId, Boolean isRemote) {
// 尝试30s
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
@ -82,19 +69,7 @@ public class JudgeServerUtils {
@Override
public void run() {
count.getAndIncrement();
JudgeServer judgeServer = chooseServer(isRemote);
if (count.get() == 30) { // 30次失败则判为提交失败
if (isRemote) { // 远程判题需要将账号归为可用
UpdateWrapper<RemoteJudgeAccount> remoteJudgeAccountUpdateWrapper = new UpdateWrapper<>();
remoteJudgeAccountUpdateWrapper
.eq("username", data.getUsername())
.eq("password", data.getPassword())
.set("status", true);
remoteJudgeAccountService.update(remoteJudgeAccountUpdateWrapper);
}
checkResult(null, submitId);
scheduler.shutdown();
}
JudgeServer judgeServer = chooseServer.choose(isRemote);
if (judgeServer != null) { // 获取到判题机资源
CommonResult result = null;
try {
@ -108,15 +83,28 @@ public class JudgeServerUtils {
scheduler.shutdown();
}
}
if (count.get() == 30) { // 30次失败则判为提交失败
if (isRemote) { // 远程判题需要将账号归为可用
UpdateWrapper<RemoteJudgeAccount> remoteJudgeAccountUpdateWrapper = new UpdateWrapper<>();
remoteJudgeAccountUpdateWrapper
.eq("username", data.getUsername())
.eq("password", data.getPassword())
.set("status", true);
remoteJudgeAccountService.update(remoteJudgeAccountUpdateWrapper);
}
checkResult(null, submitId);
scheduler.shutdown();
}
}
};
scheduler.scheduleAtFixedRate(getResultTask, 0, 1, TimeUnit.SECONDS);
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public CommonResult toCompile(String path, CompileSpj data) {
CommonResult result = CommonResult.errorResponse("没有可用的判题服务器,请重新尝试!");
JudgeServer judgeServer = chooseServer(false);
JudgeServer judgeServer = chooseServer.choose(false);
if (judgeServer != null) {
try {
result = restTemplate.postForObject("http://" + judgeServer.getUrl() + path, data, CommonResult.class);
@ -130,63 +118,6 @@ public class JudgeServerUtils {
return result;
}
/**
* @param
* @MethodName chooseServer
* @Description 选择可以用调用判题的判题服务器
* @Return
* @Since 2021/4/15
*/
public JudgeServer chooseServer(Boolean isRemote) {
// 获取该微服务的所有健康实例
List<Instance> instances = getInstances(JudgeServiceName);
if (instances.size() <= 0) {
return null;
}
List<String> keyList = new ArrayList<>();
// 获取当前健康实例取出ip和port拼接
for (Instance instance : instances) {
keyList.add(instance.getIp() + ":" + instance.getPort());
}
// 过滤出小于或等于规定最大并发判题任务数的服务实例且健康的判题机
QueryWrapper<JudgeServer> judgeServerQueryWrapper = new QueryWrapper<>();
judgeServerQueryWrapper
.in("url", keyList)
.eq("is_remote", isRemote)
.orderByAsc("task_number");
List<JudgeServer> judgeServerList = judgeServerService.list(judgeServerQueryWrapper);
// 使用乐观锁获取可用判题机
for (JudgeServer judgeServer : judgeServerList) {
if (judgeServer.getTaskNumber() < judgeServer.getMaxTaskNumber()) {
judgeServer.setTaskNumber(judgeServer.getTaskNumber() + 1);
boolean isOk = judgeServerService.updateById(judgeServer);
if (isOk) {
return judgeServer;
}
}
}
return null;
}
/**
* @param serviceId
* @MethodName getInstances
* @Description 根据服务id获取对应的健康实例列表
* @Return
* @Since 2021/4/15
*/
private List<Instance> getInstances(String serviceId) {
// 获取服务发现的相关API
NamingService namingService = discoveryProperties.namingServiceInstance();
try {
// 获取该微服务的所有健康实例
return namingService.selectInstances(serviceId, true);
} catch (NacosException e) {
log.error("获取微服务健康实例发生异常--------->{}", e);
return Collections.emptyList();
}
}
private void checkResult(CommonResult result, Long submitId) {
@ -199,6 +130,7 @@ public class JudgeServerUtils {
} else {
if (result.getStatus().intValue() != CommonResult.STATUS_SUCCESS) { // 如果是结果码不是200 说明调用有错误
// 判为系统错误
System.out.println("进来了");
judge.setStatus(Constants.Judge.STATUS_SYSTEM_ERROR.getStatus())
.setErrorMessage(result.getMsg());
judgeService.updateById(judge);
@ -207,7 +139,6 @@ public class JudgeServerUtils {
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public void reduceCurrentTaskNum(Integer id) {
UpdateWrapper<JudgeServer> judgeServerUpdateWrapper = new UpdateWrapper<>();
judgeServerUpdateWrapper.setSql("task_number = task_number-1").eq("id", id);
@ -217,7 +148,6 @@ public class JudgeServerUtils {
}
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public void tryAgainUpdate(UpdateWrapper<JudgeServer> updateWrapper) {
boolean retryable;
int attemptNumber = 0;

View File

@ -6,12 +6,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import top.hcode.hoj.judge.JudgeServerUtils;
import top.hcode.hoj.judge.Dispatcher;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.JudgeServer;
import top.hcode.hoj.pojo.entity.RemoteJudgeAccount;
import top.hcode.hoj.pojo.entity.ToJudge;
import top.hcode.hoj.service.impl.JudgeServiceImpl;
@ -23,7 +19,6 @@ import java.util.List;
import java.util.concurrent.TimeUnit;
@Component
@Async
public class RemoteJudgeReceiver {
@ -34,7 +29,7 @@ public class RemoteJudgeReceiver {
private JudgeServiceImpl judgeService;
@Autowired
private JudgeServerUtils judgeServerUtils;
private Dispatcher dispatcher;
@Autowired
private RedisUtils redisUtils;
@ -42,7 +37,7 @@ public class RemoteJudgeReceiver {
@Autowired
private RemoteJudgeAccountServiceImpl remoteJudgeAccountService;
@Transactional(isolation = Isolation.READ_COMMITTED)
@Async("judgeTaskAsyncPool")
public void processWaitingTask() {
// 如果队列中还有任务则继续处理
if (redisUtils.lGetListSize(Constants.Judge.STATUS_REMOTE_JUDGE_WAITING_HANDLE.getName()) > 0) {
@ -54,7 +49,6 @@ public class RemoteJudgeReceiver {
}
}
@Transactional(isolation = Isolation.READ_COMMITTED)
public void handleJudgeMsg(String taskJsonStr) {
JSONObject task = JSONUtil.parseObj(taskJsonStr);
@ -88,7 +82,7 @@ public class RemoteJudgeReceiver {
if (account != null) { // 如果获取到账号
// 调用判题服务
judgeServerUtils.dispatcher("judge", "/remote-judge", new ToJudge()
dispatcher.dispatcher("judge", "/remote-judge", new ToJudge()
.setJudge(judge)
.setToken(token)
.setRemoteJudge(remoteJudge)

View File

@ -6,10 +6,9 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import top.hcode.hoj.judge.JudgeServerUtils;
import top.hcode.hoj.judge.Dispatcher;
import top.hcode.hoj.pojo.entity.Judge;
import top.hcode.hoj.pojo.entity.ToJudge;
import top.hcode.hoj.service.impl.JudgeServiceImpl;
import top.hcode.hoj.utils.Constants;
import top.hcode.hoj.utils.RedisUtils;
@ -25,12 +24,12 @@ import top.hcode.hoj.utils.RedisUtils;
public class JudgeReceiver {
@Autowired
private JudgeServerUtils judgeServerUtils;
private Dispatcher dispatcher;
@Autowired
private RedisUtils redisUtils;
@Async
@Async("judgeTaskAsyncPool")
public void processWaitingTask() {
// 如果队列中还有任务则继续处理
if (redisUtils.lGetListSize(Constants.Judge.STATUS_JUDGE_WAITING.getName()) > 0) {
@ -48,9 +47,8 @@ public class JudgeReceiver {
Judge judge = task.get("judge", Judge.class);
String token = task.getStr("token");
Integer tryAgainNum = task.getInt("tryAgainNum");
// 调用判题服务
judgeServerUtils.dispatcher("judge", "/judge", new ToJudge()
dispatcher.dispatcher("judge", "/judge", new ToJudge()
.setJudge(judge)
.setToken(token)
.setRemoteJudge(null)

View File

@ -21,7 +21,7 @@ public class ConfigVo {
@Value("${hoj.db.username}")
private String mysqlUsername;
@Value("${hoj.db.password:hoj123456}")
@Value("${hoj.db.password}")
private String mysqlPassword;
@Value("${hoj.db.name}")

View File

@ -8,6 +8,8 @@ import top.hcode.hoj.dao.JudgeServerMapper;
import top.hcode.hoj.pojo.entity.JudgeServer;
import top.hcode.hoj.service.JudgeServerService;
import java.util.List;
/**
* @Author: Himit_ZH
* @Date: 2021/4/15 11:27
@ -16,5 +18,4 @@ import top.hcode.hoj.service.JudgeServerService;
@Service
public class JudgeServerServiceImpl extends ServiceImpl<JudgeServerMapper, JudgeServer> implements JudgeServerService {
}

View File

@ -1,6 +1,6 @@
hoj-backstage:
port: ${BACKEND_SERVER_PORT:6688} # 本服务器启动的端口号
nacos-url: ${NACOS_URL:172.20.0.4:8848} # nacos的地址
nacos-url: ${NACOS_URL:129.204.177.72:8848} # nacos的地址
server:
port: ${hoj-backstage.port}
spring:

View File

@ -4,6 +4,7 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
* @Author: Himit_ZH
@ -13,6 +14,7 @@ import org.springframework.scheduling.annotation.EnableAsync;
@EnableDiscoveryClient
@SpringBootApplication
@EnableAsync(proxyTargetClass=true) //开启异步注解
@EnableTransactionManagement
public class JudgeServerApplication {
public static void main(String[] args) {
SpringApplication.run(JudgeServerApplication.class,args);

View File

@ -24,6 +24,8 @@ public class AsyncTaskConfig implements AsyncConfigurer {
taskExecutor.setMaxPoolSize(50);
// 缓存队列
taskExecutor.setQueueCapacity(200);
//活跃时间
taskExecutor.setKeepAliveSeconds(10);
// 对拒绝task的处理策略
//(1) 默认的ThreadPoolExecutor.AbortPolicy 处理程序遭到拒绝将抛出运行时RejectedExecutionException;
//(2) ThreadPoolExecutor.CallerRunsPolicy 线程调用运行该任务的 execute 本身此策略提供简单的反馈控制机制能够减缓新任务的提交速度

View File

@ -61,7 +61,6 @@ public class StartupRunner implements CommandLineRunner {
.setCpuCore(cpuNum)
.setIp(ip)
.setPort(port)
.setVersion(0L)
.setUrl(ip + ":" + port)
.setMaxTaskNumber(maxTaskNum)
.setIsRemote(false)
@ -75,7 +74,6 @@ public class StartupRunner implements CommandLineRunner {
.setCpuCore(cpuNum)
.setIp(ip)
.setPort(port)
.setVersion(0L)
.setUrl(ip + ":" + port)
.setMaxTaskNumber(maxRemoteTaskNum)
.setIsRemote(true)

View File

@ -153,7 +153,7 @@ public class Constants {
PYTHON2("Python2", "main.py", "main.pyc", 3000L, 10000L, 128 * 1024 * 1024L, "/usr/bin/python -m py_compile ./{1}", defaultEnv),
PYTHON3("Python3", "main.py", "__pycache__/main.cpython-37.pyc", 3000L, 10000L, 128 * 1024 * 1024L, "/usr/bin/python3 -m py_compile ./{1}", defaultEnv),
PYTHON3("Python3", "main.py", "__pycache__/main.cpython-36.pyc", 3000L, 10000L, 128 * 1024 * 1024L, "/usr/bin/python3 -m py_compile ./{1}", defaultEnv),
GOLANG("Golang", "main.go", "main", 3000L, 5000L, 512 * 1024 * 1024L, "/usr/bin/go build -o {2} {1}", defaultEnv),

View File

@ -40,7 +40,7 @@ logging:
nacos: error
root: error
config: classpath:logback-spring.xml
path: /hoj/log/backend/hoj_judgeserver.log
path: /hoj/log/judgeserver/hoj_judgeserver.log
# 暴露监控
management:
endpoints:

View File

@ -48,10 +48,6 @@ public class JudgeServer {
@ApiModelProperty(value = "0可用1不可用")
private Integer status;
@Version
@TableField(fill = FieldFill.INSERT)
private Long version;
@ApiModelProperty(value = "是否为远程判题vj")
private Boolean isRemote;

Binary file not shown.

View File

@ -0,0 +1,5 @@
#Generated by Maven
#Mon May 24 19:05:59 CST 2021
version=1.0-SNAPSHOT
groupId=top.hcode
artifactId=api

View File

@ -0,0 +1,29 @@
top\hcode\hoj\pojo\entity\File.class
top\hcode\hoj\pojo\entity\UserInfo.class
top\hcode\hoj\pojo\entity\ContestRegister.class
top\hcode\hoj\pojo\entity\Session.class
top\hcode\hoj\pojo\entity\RoleAuth.class
top\hcode\hoj\pojo\entity\Discussion.class
top\hcode\hoj\pojo\entity\RemoteJudgeAccount.class
top\hcode\hoj\pojo\entity\Role.class
top\hcode\hoj\pojo\entity\ContestExplanation.class
top\hcode\hoj\pojo\entity\ToJudge.class
top\hcode\hoj\pojo\entity\ContestProblem.class
top\hcode\hoj\pojo\entity\DiscussionLike.class
top\hcode\hoj\pojo\entity\ProblemTag.class
top\hcode\hoj\pojo\entity\Problem.class
top\hcode\hoj\pojo\entity\Tag.class
top\hcode\hoj\pojo\entity\ProblemLanguage.class
top\hcode\hoj\pojo\entity\DiscussionReport.class
top\hcode\hoj\pojo\entity\UserRecord.class
top\hcode\hoj\pojo\entity\ContestScore.class
top\hcode\hoj\pojo\entity\ProblemCase.class
top\hcode\hoj\pojo\entity\ProblemCount.class
top\hcode\hoj\pojo\entity\Judge.class
top\hcode\hoj\pojo\entity\ContestRecord.class
top\hcode\hoj\pojo\entity\Language.class
top\hcode\hoj\pojo\entity\JudgeCase.class
top\hcode\hoj\pojo\entity\JudgeServer.class
top\hcode\hoj\pojo\entity\UserAcproblem.class
top\hcode\hoj\pojo\entity\UserRole.class
top\hcode\hoj\pojo\entity\Reply.class

View File

@ -0,0 +1,38 @@
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Announcement.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Auth.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Discussion.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\UserInfo.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ProblemCase.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ContestScore.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\DiscussionReport.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\CommentLike.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\DiscussionLike.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\RemoteJudgeAccount.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Tag.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\UserAcproblem.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ProblemLanguage.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Comment.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ProblemCount.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ContestRegister.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Session.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\CodeTemplate.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Contest.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\JudgeCase.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\UserRecord.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\RoleAuth.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ToJudge.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\CompileSpj.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ProblemTag.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Language.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ContestRecord.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Judge.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Problem.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\UserRole.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\File.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Category.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ContestAnnouncement.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Reply.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\Role.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\JudgeServer.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ContestProblem.java
E:\code\Gitee\hoj\hoj-springboot\api\src\main\java\top\hcode\hoj\pojo\entity\ContestExplanation.java