OJ判题系统异常处理
环境
- MacBook M2 PRO
- Docker27.x
- Java 1.8
沙箱不断输出内存信息(Docker版)
为什么在本地Main方法测试一切正常,当前端传入代码在沙箱执行时候却不断打印内存信息?
解决方案:关闭正在运行中的容器
当我们关闭Docker 正在运行的容器后 获取内存占用才真正完成
▼java复制代码@Override public void close() throws IOException { log.info("尝试关闭 获取内存占用 "); try { // 停止容器 dockerClient.stopContainerCmd(containerId).exec(); System.out.println("容器已停止:" + containerId); // 删除容器 dockerClient.removeContainerCmd(containerId).exec(); System.out.println("容器已删除:" + containerId); } catch (Exception e) { System.out.println("停止或删除容器时发生异常:" + e.getMessage()); } }
原因
当我们提交的代码在Docker容器执行完成后,但是容器仍然在运行。所以会不断的获取内存占用的信息输出。
代码沙箱执行完成后,OJ后台关键信息为空?(Docker版)
解决方案: 重写getOutputResponse()
#javaDockerCodeSandbox
▼java复制代码@Override public ExecuteCodeResponse getOutputResponse(List<ExecuteMessage> executeMessageList) { JudgeInfo judgeInfo = new JudgeInfo(); ... //获取最大内存 judgeInfo.setMemory(executeMessage.getMemory()); //获取最大时间 judgeInfo.setTime(executeMessage.getTime()); //获取最大输出 judgeInfo.setMessage(executeMessage.getMessage()); .... executeCodeResponse.setJudgeInfo(judgeInfo); //完成代码看下方原因
原因
大致梳理下整体用户提交代码到返回沙箱判题结果的流程
#JudgeServiceImpl 1.封装执行代码请求信息,调用代码沙箱执行
▼java复制代码ExecuteCodeResponse executeCodeResponse = codeSandbox.executeCode(executeCodeRequest);
2.这里用的是远程代码沙箱,最终的请求从这里发出到代码沙箱(关键点!!!) #RemoteCodeSandbox
#javaDockerCodeSandbox 3.从代码沙箱入手调试到这一步,有我们需要的 - 内存(memory) - 时间(time)
- 思考:既然代码沙箱执行完成后,有我们需要的信息。为什么在OJ后台却为空呢?
答案就在明面上,在封装代码沙箱返回到OJ后台的信息并不完整
4.代码沙箱执行完成后我们回到OJ后台查看,关键信息都是没有的
顺藤摸瓜,这些信息从哪里封装的? #javaDockerCodeSandbox
使用了模版方法优化,但只重写runFile()方法所以封装沙箱结果还用的是
#javaDockerCodeSandboxTemplate 的getOutputResponse()
源赖氏妹封装啊!
后面拓展实现其他沙箱获取内存的方式可能不相同, 作者选择重写getOutputResponse()
▼java复制代码/** * 5.获取输出结果 * * @param executeMessageList * @return {@link ExecuteCodeResponse } */@Override public ExecuteCodeResponse getOutputResponse(List<ExecuteMessage> executeMessageList) { JudgeInfo judgeInfo = new JudgeInfo(); ExecuteCodeResponse executeCodeResponse = new ExecuteCodeResponse(); List<String> outputList = new ArrayList<>(); //取用时最大值,便于判断是否超时 long maxTime = 0; for (ExecuteMessage executeMessage : executeMessageList) { String errorMessage = executeMessage.getErrorMessage(); if (StrUtil.isNotBlank(errorMessage)) { executeCodeResponse.setMessage(errorMessage); // 用户提交的代码执行中存在错误 // todo 设置枚举值 executeCodeResponse.setStatus(3); break; } outputList.add(executeMessage.getMessage()); Long time = executeMessage.getTime(); if (time != null) { maxTime = Math.max(maxTime, time); } //获取最大内存 judgeInfo.setMemory(executeMessage.getMemory()); //获取最大时间 judgeInfo.setTime(executeMessage.getTime()); //获取最大输出 judgeInfo.setMessage(executeMessage.getMessage()); } // 正常运行完成 if (outputList.size() == executeMessageList.size()) { // todo 设置枚举值 executeCodeResponse.setStatus(1); } executeCodeResponse.setOutputList(outputList); executeCodeResponse.setJudgeInfo(judgeInfo); return executeCodeResponse; }
最后
非常感谢您读到这里!希望本文为您提供了有价值的信息。 如果有任何疑问或者建议,欢迎在评论区留言 期待大家的宝贵意见!
我是Sion ,代码世界的茄咧啡。
评论
问答助学
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
内容推荐
AI应用开发中的流式输出:从协议原理到工程实战的完整指南
38
第1章 LearnWise AI项目介绍
5
Spring Boot 如何处理跨域请求(CORS):深度调研报告
3
【入职求助贴】萌新刚入职某大厂做后端开发,目前还在试用期。最近遇到一个棘手的问题,想向大家求助一下。入职不久,leader 给我派了一个任务。跟我说是0.5天就可以解决,我刚毕业入职,做了一个星期没有做出来。实现一个收集定时成功任务的案例。听起来好像不复杂,但我自己摸索着做了一整个星期,到现在还没达到预期效果。这一周我基本是“边学边做”的状态,遇到卡点也会每天主动找 leader 沟通进度和疑问。
2
#字节内推# 实习、校招、社招均有岗位
4
