HimitZH / HOJ

⚡🔥Hcode Online Judge(HOJ)🔥⚡:基于SpringCloud与Vue前后端分离,分布式架构的在线测评平台OJ (An open source online judge system base on SpringBoot, Springcloud Alibaba and Vue.js !)
https://docs.hdoi.cn
MIT License
669 stars 147 forks source link

关于重试机制的一些问题 #55

Closed sundongyu closed 8 months ago

sundongyu commented 8 months ago

尊敬的开发者您好,最近在阅读您的项目代码,存在一个疑问,希望您能在闲暇之余给予解惑。

对于一个评测请求发送到Redis中对应的等待队列后,将会调用判题服务:

if (isContest) {
    isOk = redisUtils.llPush(Constants.Queue.CONTEST_JUDGE_WAITING.getName(), JSONUtil.toJsonStr(task));
} else {
    isOk = redisUtils.llPush(Constants.Queue.GENERAL_JUDGE_WAITING.getName(), JSONUtil.toJsonStr(task));
}
...
// 调用判题任务处理
judgeReceiver.processWaitingTask();

在 judgeReceiver.processWaitingTask() 方法中按照(比赛、评测、调试)优先级处理Redis等待队列中的任务(通过redisUtils.lrPop(queue)获取并删除等待队列中一个任务),然后在handleJudgeMsg方法中处理:

public void handleJudgeMsg(String taskStr, String queueName) {
        ...

    // 调用判题服务
    dispatcher.dispatch(Constants.TaskType.JUDGE, new ToJudgeDTO()
            .setJudge(judge)
            .setToken(token)
            .setRemoteJudgeProblem(null));
        ...
    // 接着处理任务
    processWaitingTask();
}

最后,代码来到defaultJudge方法,该方法是向判题机发送请求并处理重试判题的方法,在该方法中定义了一个用于每间隔2秒重复执行的任务 scheduler.scheduleWithFixedDelay(getResultTask, 0, 2, TimeUnit.SECONDS); 然而在任务代码中,releaseTaskThread(taskKey)方法是用于该任务释放的,可是这个代码却放在finally代码块中,这意味着无论该任务执行成功与否,在finally代码块中都会将该任务关闭,然而此时Redis的等待队列中已经将该任务删除,因此我好奇如何进行任务执行的重试操作

public void defaultJudge(ToJudgeDTO data, String path) {

        Runnable getResultTask = () -> {
            if (count.get() > maxTryNum) {
                releaseTaskThread(taskKey);
                return;
            }
            if (judgeServer != null) { 
            ...
                try {
                   ...
                } catch (Exception e) {
                    ...
                } finally {
                    ...
                    releaseTaskThread(taskKey);
                }
            }
        };
        ScheduledFuture<?> scheduledFuture = scheduler.scheduleWithFixedDelay(getResultTask, 0, 2, TimeUnit.SECONDS);
        futureTaskMap.put(taskKey, scheduledFuture);
    }

当然也很有可能是我理解错误或者部分代码没有注意到,总之,期待您的回复。