From 4b724ea301458c0b453b894a2cb95c0ee6dcec4f Mon Sep 17 00:00:00 2001 From: Rintaro Ishizaki Date: Fri, 29 May 2026 11:58:06 -0700 Subject: [PATCH] Drain pending tasks in TaskScheduler shutdown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `shutDown` only cancels `currentlyExecutingTasks`, leaving `pendingTasks` untouched. External callers awaiting `waitToFinish()` on a pending task hang forever — `resultTask` keeps awaiting an `AsyncStream` that the scheduler will never yield into once `isShutDown` is set — and each such `QueuedTask` is leaked via the strong cycle through its `resultTask` closure. Cancel pending tasks too: `task.cancel()` cancels `resultTask`, the `for await` over the stream exits immediately on cancellation, and `waitToFinish()` returns in microseconds. --- Sources/SemanticIndex/TaskScheduler.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Sources/SemanticIndex/TaskScheduler.swift b/Sources/SemanticIndex/TaskScheduler.swift index e9b1c3a9d..533197fba 100644 --- a/Sources/SemanticIndex/TaskScheduler.swift +++ b/Sources/SemanticIndex/TaskScheduler.swift @@ -459,7 +459,8 @@ package actor TaskScheduler { /// After `shutDown` has been called, no more tasks will be executed on this `TaskScheduler`. package func shutDown() async { self.isShutDown = true - await self.currentlyExecutingTasks.concurrentForEach { task in + let allTasks = self.currentlyExecutingTasks + self.pendingTasks + await allTasks.concurrentForEach { task in task.cancel() do { try await withTimeout(.seconds(10)) {