Himit_ZH
This commit is contained in:
parent
a518fea2ed
commit
380e385440
|
@ -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 |
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -23,3 +23,4 @@ pnpm-debug.log*
|
|||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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> {
|
||||
|
||||
}
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
||||
}
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
#Generated by Maven
|
||||
#Mon May 24 19:05:59 CST 2021
|
||||
version=1.0-SNAPSHOT
|
||||
groupId=top.hcode
|
||||
artifactId=api
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue