Merge pull request #1811 from QwenLM/fix/abort-signal-listener-leak
Some checks are pending
Qwen Code CI / Lint (push) Waiting to run
Qwen Code CI / Test (push) Blocked by required conditions
Qwen Code CI / Test-1 (push) Blocked by required conditions
Qwen Code CI / Test-2 (push) Blocked by required conditions
Qwen Code CI / Test-3 (push) Blocked by required conditions
Qwen Code CI / Test-4 (push) Blocked by required conditions
Qwen Code CI / Test-5 (push) Blocked by required conditions
Qwen Code CI / Test-6 (push) Blocked by required conditions
Qwen Code CI / Test-7 (push) Blocked by required conditions
Qwen Code CI / Test-8 (push) Blocked by required conditions
Qwen Code CI / Post Coverage Comment (push) Blocked by required conditions
Qwen Code CI / CodeQL (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:docker (push) Waiting to run
E2E Tests / E2E Test (Linux) - sandbox:none (push) Waiting to run
E2E Tests / E2E Test - macOS (push) Waiting to run

fix: prevent AbortSignal listener memory leak
This commit is contained in:
顾盼 2026-02-13 10:35:20 +08:00 committed by GitHub
commit aefea076b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 26 additions and 5 deletions

View file

@ -80,6 +80,8 @@ export class ControlDispatcher implements IPendingRequestRegistry {
private pendingOutgoingRequests: Map<string, PendingOutgoingRequest> =
new Map();
private abortHandler: (() => void) | null = null;
constructor(context: IControlContext) {
this.context = context;
@ -102,9 +104,10 @@ export class ControlDispatcher implements IPendingRequestRegistry {
// this.hookController = new HookController(context, this, 'HookController');
// Listen for main abort signal
this.context.abortSignal.addEventListener('abort', () => {
this.abortHandler = () => {
this.shutdown();
});
};
this.context.abortSignal.addEventListener('abort', this.abortHandler);
}
/**
@ -240,6 +243,12 @@ export class ControlDispatcher implements IPendingRequestRegistry {
shutdown(): void {
debugLogger.debug('[ControlDispatcher] Shutting down');
// Remove abort listener to prevent memory leak
if (this.abortHandler) {
this.context.abortSignal.removeEventListener('abort', this.abortHandler);
this.abortHandler = null;
}
// Cancel all incoming requests
for (const [
_requestId,

View file

@ -408,7 +408,8 @@ class Session {
private handleInterrupt(): void {
debugLogger.info('[Session] Interrupt requested');
this.abortController.abort();
this.abortController = new AbortController();
// Do not create a new AbortController to prevent listener leaks.
// Subsequent queries will check signal.aborted and fail immediately.
}
private setupSignalHandlers(): void {