fix: defer stuck-kill requeue to executor finally block to prevent race
When the stuck task detector killed a task and immediately called
moveTask("todo"), the scheduler could re-dispatch the task before the
old execution's finally block cleared this.executing. The new execute()
call hit the guard and silently returned, stranding the task in
"in-progress" with no active session or worktree (seen on FN-810/FN-912).
Move the requeue responsibility from StuckTaskDetector.killAndRetry to
the executor's finally block, which runs after this.executing.delete().
The beforeRequeue budget check now runs before session.dispose() and its
result is passed via StuckTaskEvent.shouldRequeue → markStuckAborted().
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -578,12 +578,12 @@ export async function runDashboard(port: number, opts: { paused?: boolean; dev?:
|
||||
const stuckTaskDetector = new StuckTaskDetector(store, {
|
||||
beforeRequeue: (taskId) => selfHealing.checkStuckBudget(taskId),
|
||||
onStuck: (event) => {
|
||||
executorRef.current?.markStuckAborted(event.taskId);
|
||||
executorRef.current?.markStuckAborted(event.taskId, event.shouldRequeue);
|
||||
console.log(
|
||||
`[engine] ⚠ ${event.taskId} stuck (${event.reason}) — ` +
|
||||
`no progress for ${Math.round(event.noProgressMs / 60_000)}min, ` +
|
||||
`${event.activitySinceProgress} events since last progress — ` +
|
||||
`terminated, will retry`,
|
||||
`terminated, ${event.shouldRequeue ? "will retry" : "budget exhausted"}`,
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user