fix(FN-2054): harden agent loop stuck-detection and self-healing
- Add defensive cleanup for in-memory task tracking when tasks move state or agents pause - Improve stuck-detection and self-healing flow to reduce leaked state and missed recovery paths - Add logging around previously swallowed errors and tighten executor cleanup behavior - Expand restart and self-healing reliability tests to cover regression scenarios
This commit is contained in:
@@ -670,6 +670,21 @@ export class Scheduler {
|
||||
reservedWorktreeNames,
|
||||
);
|
||||
|
||||
// Compare-and-swap: re-read the task to verify it's still in "todo" before dispatching.
|
||||
// This prevents dispatching a task twice if another schedule() call or user action
|
||||
// moved it away from "todo" between our initial snapshot and this dispatch attempt.
|
||||
// The re-entrance guard prevents overlapping schedule() passes, but external events
|
||||
// (user moves, API calls) can still trigger concurrent state changes.
|
||||
const freshTask = await this.store.getTask(task.id);
|
||||
if (!freshTask || freshTask.column !== "todo") {
|
||||
schedulerLog.log(`Task ${task.id} no longer in "todo" (column=${freshTask?.column ?? "N/A"}) — skipping dispatch`);
|
||||
continue;
|
||||
}
|
||||
if (freshTask.paused) {
|
||||
schedulerLog.log(`Task ${task.id} is paused — skipping dispatch`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Clear status, reserve worktree path, and then move to in-progress
|
||||
schedulerLog.log(`Starting ${task.id}: ${task.title || task.id} (deps satisfied)`);
|
||||
await this.store.updateTask(task.id, {
|
||||
|
||||
Reference in New Issue
Block a user