fix: Prevent FileSystemWatcher leak in RooIgnoreController (#4233)

* fix: auto patch for RooIgnoreController_41

* fix: improve error handling during task disposal and cleanup
This commit is contained in:
kiwina 2025-06-05 04:54:24 +08:00 • committed by GitHub
parent c02e01ed69
commit 6f21103545
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -977,6 +977,59 @@ export class Task extends EventEmitter<ClineEvents> {
await this.initiateTaskLoop(newUserContent)
}
public dispose(): void {
// Stop waiting for child task completion.
if (this.pauseInterval) {
clearInterval(this.pauseInterval)
this.pauseInterval = undefined
}
// Release any terminals associated with this task.
try {
// Release any terminals associated with this task.
TerminalRegistry.releaseTerminalsForTask(this.taskId)
} catch (error) {
console.error("Error releasing terminals:", error)
}
try {
this.urlContentFetcher.closeBrowser()
} catch (error) {
console.error("Error closing URL content fetcher browser:", error)
}
try {
this.browserSession.closeBrowser()
} catch (error) {
console.error("Error closing browser session:", error)
}
try {
if (this.rooIgnoreController) {
this.rooIgnoreController.dispose()
this.rooIgnoreController = undefined
}
} catch (error) {
console.error("Error disposing RooIgnoreController:", error)
// This is the critical one for the leak fix
}
try {
this.fileContextTracker.dispose()
} catch (error) {
console.error("Error disposing file context tracker:", error)
}
try {
// If we're not streaming then `abortStream` won't be called
if (this.isStreaming && this.diffViewProvider.isEditing) {
this.diffViewProvider.revertChanges().catch(console.error)
}
} catch (error) {
console.error("Error reverting diff changes:", error)
}
}
public async abortTask(isAbandoned = false) {
console.log(`[subtasks] aborting task ${this.taskId}.${this.instanceId}`)
@ -988,28 +1041,19 @@ export class Task extends EventEmitter<ClineEvents> {
this.abort = true
this.emit("taskAborted")
// Stop waiting for child task completion.
if (this.pauseInterval) {
clearInterval(this.pauseInterval)
this.pauseInterval = undefined
try {
this.dispose() // Call the centralized dispose method
} catch (error) {
console.error(`Error during task ${this.taskId}.${this.instanceId} disposal:`, error)
// Don't rethrow - we want abort to always succeed
}
// Release any terminals associated with this task.
TerminalRegistry.releaseTerminalsForTask(this.taskId)
this.urlContentFetcher.closeBrowser()
this.browserSession.closeBrowser()
this.rooIgnoreController?.dispose()
this.fileContextTracker.dispose()
// If we're not streaming then `abortStream` (which reverts the diff
// view changes) won't be called, so we need to revert the changes here.
if (this.isStreaming && this.diffViewProvider.isEditing) {
await this.diffViewProvider.revertChanges()
}
// Save the countdown message in the automatic retry or other content.
await this.saveClineMessages()
try {
// Save the countdown message in the automatic retry or other content.
await this.saveClineMessages()
} catch (error) {
console.error(`Error saving messages during abort for task ${this.taskId}.${this.instanceId}:`, error)
}
}
// Used when a sub-task is launched and the parent task is waiting for it to