Skip to content

Commit 6fc76ad

Browse files
authored
Close executors that Shutdown invalidates while their Run retires (#482)
Shutdown marks every executor invalid but closes only owners without a Run, leaving a running owner's close to its prepared release. The release reads r.closed and owner.invalid once, before joining operations and retiring the Run. When Shutdown took the lock after that reuse decision and before the Run let go of the owner, nobody closed the executor: it stayed in r.executors with no close in flight, and Shutdown reported "cleanup unconfirmed" for a healthy native executor. Device shutdown has the same window and left the owner permanently invalid. When the release retires an owner that was invalidated without a close, start the close under shutdownWG so Shutdown waits for it. Report an executor that remains without a close error as "cleanup has not settled" instead of wrapping a nil error.
1 parent e60d8ff commit 6fc76ad

2 files changed

Lines changed: 10 additions & 1 deletion

File tree

‎apps/daemon/internal/dispatch/prepared_handoff.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ func (r *Router) runPreparedRelease(state *sessionState, handoff *preparedHandof
262262
}
263263
if !owner.invalid {
264264
r.scheduleExecutorIdleLocked(owner)
265+
} else if owner.closeDone == nil {
266+
// Shutdown invalidated this owner after the reuse decision above and
267+
// left its close to this Run, which held it.
268+
r.shutdownWG.Add(1)
269+
go func() { defer r.shutdownWG.Done(); _ = r.closeExecutor(owner) }()
265270
}
266271
r.mu.Unlock()
267272

‎apps/daemon/internal/dispatch/shutdown.go‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,11 @@ func (r *Router) runShutdownAttempt(attempt *shutdownAttempt, victims []sessionC
9090
}
9191
}
9292
for _, owner := range r.executors {
93-
attempt.err = errors.Join(attempt.err, fmt.Errorf("dispatch: executor %s cleanup unconfirmed: %w", owner.id, owner.closeErr))
93+
cause := owner.closeErr
94+
if cause == nil {
95+
cause = errors.New("cleanup has not settled")
96+
}
97+
attempt.err = errors.Join(attempt.err, fmt.Errorf("dispatch: executor %s: %w", owner.id, cause))
9498
}
9599
close(attempt.done)
96100
r.mu.Unlock()

0 commit comments

Comments
 (0)