保存任务时递归循环检测异常:next_job为0仍误判存在递归
修复任务递归循环检测的问题
核心问题分析
你的代码误判无后续任务(next_job=0)为递归的根本原因是:检测循环时使用的是数据库中的旧任务数据,而非当前要保存的最新配置。当你修改任务的next_job为0时,checkLoop函数仍然从数据库读取旧的next_job值(比如之前的3)进行检测,导致错误判定存在循环。
修复步骤及代码
1. 用最新数据覆盖旧数据
在checkLoop函数中,加载数据库任务后,必须将当前要保存的$data覆盖到任务列表中,确保检测的是最新的配置:
private function checkLoop($data) { $visited = []; $stack = []; $jobs = $db->getJobsFromDatabase(); foreach ($jobs as $job) { $this->jobs[$job->id] = $job; } // 关键:用当前要保存的最新数据替换旧数据 $currentJob = (object)$data; $this->jobs[$currentJob->id] = $currentJob; // 基于更新后的任务检测循环 if ($this->checkLoopRecursive($currentJob->id, $visited, $stack)) { echo "> REKURSIVE"; return true; } echo "> NO REKURSION"; return false; }
2. 优化递归检测逻辑
调整递归函数,明确处理next_job=0的场景,同时增加任务不存在的边界判断:
private function checkLoopRecursive($job_id, &$visited, &$stack) { // 任务不存在时直接返回无循环 if (!isset($this->jobs[$job_id])) { return false; } if (!isset($visited[$job_id])) { $visited[$job_id] = true; $stack[$job_id] = true; $next_job_id = (int)$this->jobs[$job_id]->next_job; if ($next_job_id !== 0) { // 递归检测下一个任务,若返回true则存在循环 if ($this->checkLoopRecursive($next_job_id, $visited, $stack)) { return true; } } } elseif (isset($stack[$job_id])) { // 当前任务已在递归栈中,说明形成循环 return true; } // 退出当前递归栈 $stack[$job_id] = false; return false; }
3. 验证onSave逻辑
原onSave函数的判断逻辑是合理的,仅当设置了有效next_job时才检测循环,无需修改:
public function onSave($data) { $next_job_id = (int)$data['next_job']; if ($next_job_id > 0 && $this->checkLoop($data)) { $this->error('Loop happening'); return false; } return $data; }
修复后的效果
- 当任务设置next_job=0时,会直接终止递归链,正确判定为无循环
- 当设置有效next_job时,会基于最新配置检测是否形成闭环
- 新增任务不存在的边界处理,避免空指针错误
内容的提问来源于stack exchange,提问作者maidan
相关产品推荐
相关产品推荐

