Skip to content

Commit 9a45dc1

Browse files
committed
fix(child-process-utils): correct handling of iteration interruption
1 parent a86843a commit 9a45dc1

File tree

2 files changed

+44
-4
lines changed

2 files changed

+44
-4
lines changed

packages/child-process-utils/src/index.spec.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,32 @@ describe('child-process-utils', () => {
7979
}
8080
}).rejects.toThrow('Process exited with non-zero code')
8181
})
82+
83+
it('should kill process on loop break', async () => {
84+
const childProcess = child(`
85+
(async () => {
86+
for (let i = 3; i > 0; i--) {
87+
console.log('log' + i)
88+
await new Promise((resolve) => setTimeout(resolve, 1000))
89+
}
90+
})()
91+
`)
92+
const output = outputStream(childProcess)
93+
const start = Date.now()
94+
let result = ''
95+
96+
for await (const line of output) {
97+
result = line.toString()
98+
break
99+
}
100+
101+
await exitCode(childProcess)
102+
103+
const end = Date.now()
104+
105+
expect(result).toBe('log3\n')
106+
expect(end - start).toBeLessThan(100)
107+
})
82108
})
83109

84110
describe('output', () => {

packages/child-process-utils/src/index.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,27 @@ export async function throwProcessError(process: ChildProcess) {
6464
* @yields The stdout of the process.
6565
*/
6666
export async function* outputStream(process: ChildProcess) {
67-
const error = throwProcessError(process)
67+
const { stdout } = process
68+
const errorPromise = catchProcessError(process)
6869

69-
if (process.stdout) {
70-
yield* process.stdout as AsyncIterable<Buffer>
70+
if (stdout) {
71+
stdout.on('error', (err) => {
72+
// Iteration was interrupted, e.g. by `break` or `return` in a for-await loop.
73+
if (err.name === 'AbortError' && process.exitCode === null) {
74+
process.kill('SIGKILL')
75+
}
76+
})
77+
78+
yield* stdout as AsyncIterable<Buffer>
7179
}
7280

73-
await error
81+
// Handle error only if iteration was not interrupted.
82+
83+
const error = await errorPromise
84+
85+
if (error) {
86+
throw error
87+
}
7488
}
7589

7690
/**

0 commit comments

Comments
 (0)