Skip to content

Commit cf0878b

Browse files
committed
Fix cycle detection on the planner
Loop detection was being performed in the wrong step in the planning process. This now moves detection when selecting candidates to make sure none of the tasks in the new candidate workflow conflict with any existing tasks. Change-type: patch
1 parent a164030 commit cf0878b

File tree

2 files changed

+8
-16
lines changed

2 files changed

+8
-16
lines changed

src/planner/mod.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ enum SearchFailed {
3838
#[error("task not applicable")]
3939
EmptyTask,
4040

41-
#[error("loop detected")]
42-
LoopDetected,
43-
4441
// this is probably a bug if this error
4542
// happens
4643
#[error("internal error: {0:?}")]
@@ -191,12 +188,6 @@ impl Planner {
191188
Task::Action(action) => {
192189
let work_id = WorkUnit::new_id(action, cur_state.root());
193190

194-
// Detect loops first, if the same action is being applied to the same
195-
// state then abort this search branch
196-
if cur_plan.as_dag().any(|a| a.id == work_id) {
197-
return Err(SearchFailed::LoopDetected)?;
198-
}
199-
200191
// Simulate the task and get the list of changes
201192
let patch = action.dry_run(cur_state).map_err(SearchFailed::BadTask)?;
202193
if patch.is_empty() {
@@ -398,8 +389,7 @@ impl Planner {
398389
}
399390

400391
// Non-critical errors are ignored (loop, empty, condition failure)
401-
Err(SearchFailed::LoopDetected)
402-
| Err(SearchFailed::EmptyTask)
392+
Err(SearchFailed::EmptyTask)
403393
| Err(SearchFailed::BadTask(task::Error::ConditionFailed)) => {}
404394

405395
// Critical internal errors terminate the search
@@ -520,11 +510,17 @@ impl Planner {
520510
.with_context(|| "failed to apply patch")
521511
.map_err(InternalError::from)?;
522512

513+
// Check if the new workflow contains any visited tasks
514+
if cur_plan.0.any(|unit| workflow.any(|u| u.id == unit.id)) {
515+
// skip this candidate because it is creating a loop
516+
continue;
517+
}
518+
523519
// Extend current plan
524520
let Workflow(cur_plan) = cur_plan.clone();
525521
let new_plan = Workflow(cur_plan + workflow);
526522

527-
// Add updated plan/state to the search stack
523+
// Add the new plan to the search stack
528524
stack.push((new_sys, new_plan, depth + 1));
529525
}
530526
}

src/workflow/mod.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,6 @@ impl From<ExecutionStatus> for WorkflowStatus {
158158
}
159159

160160
impl Workflow {
161-
pub(crate) fn as_dag(&self) -> &Dag<WorkUnit> {
162-
&self.0
163-
}
164-
165161
/// Return `true` if the Workflow's internal graph has no elements
166162
pub fn is_empty(&self) -> bool {
167163
self.0.is_empty()

0 commit comments

Comments
 (0)