From c6d94d4bf406fc3c1213210c02ea3c8ac1b0dda8 Mon Sep 17 00:00:00 2001 From: Shirone Date: Sun, 4 Jan 2026 03:50:17 +0100 Subject: [PATCH] fix: improve abort handling in spawnJSONLProcess - Added immediate invocation of abort handler if the abort signal is already triggered, ensuring proper cleanup. - Updated test to use setImmediate for aborting, allowing the generator to start processing before the abort is called, enhancing reliability. --- libs/platform/src/subprocess.ts | 7 ++++++- libs/platform/tests/subprocess.test.ts | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/libs/platform/src/subprocess.ts b/libs/platform/src/subprocess.ts index ddfa220e..7d079863 100644 --- a/libs/platform/src/subprocess.ts +++ b/libs/platform/src/subprocess.ts @@ -97,7 +97,12 @@ export async function* spawnJSONLProcess(options: SubprocessOptions): AsyncGener } childProcess.kill('SIGTERM'); }; - abortController.signal.addEventListener('abort', abortHandler); + // Check if already aborted, if so call handler immediately + if (abortController.signal.aborted) { + abortHandler(); + } else { + abortController.signal.addEventListener('abort', abortHandler); + } } // Helper to clean up abort listener diff --git a/libs/platform/tests/subprocess.test.ts b/libs/platform/tests/subprocess.test.ts index 099d084d..47119cf0 100644 --- a/libs/platform/tests/subprocess.test.ts +++ b/libs/platform/tests/subprocess.test.ts @@ -245,7 +245,7 @@ describe('subprocess.ts', () => { const mockProcess = createMockProcess({ stdoutLines: ['{"type":"start"}'], exitCode: 0, - delayMs: 100, // Delay to allow abort + delayMs: 200, // Delay to allow abort }); vi.mocked(cp.spawn).mockReturnValue(mockProcess); @@ -258,8 +258,11 @@ describe('subprocess.ts', () => { // Start consuming the generator const promise = collectAsyncGenerator(generator); - // Abort after a short delay - setTimeout(() => abortController.abort(), 20); + // Abort after a short delay to ensure generator has started + // Use setImmediate to ensure the generator has started processing + setImmediate(() => { + abortController.abort(); + }); await promise;