Skip to content

Commit 3dbb87a

Browse files
authored
feat(npm): forward termination signals to child process (#12441)
fix(npm): forward termination signals to child process
1 parent afeb55a commit 3dbb87a

File tree

1 file changed

+27
-8
lines changed

1 file changed

+27
-8
lines changed

npm/src/bin.mjs

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,21 @@ if (!platformPackage) {
2929
}
3030

3131
const child = NodeChildProcess.spawn(
32-
selectBinaryPath(),
33-
process.argv.slice(2),
34-
{ stdio: 'inherit' }
32+
selectBinaryPath(),
33+
process.argv.slice(2),
34+
{ stdio: 'inherit' }
3535
)
3636

37-
process.on('SIGINT', killChild)
38-
process.on('SIGTERM', killChild)
37+
/**
38+
* @type {Record<'SIGINT' | 'SIGTERM', () => void>}
39+
*/
40+
const signalHandlers = {
41+
SIGINT: () => forwardSignal('SIGINT'),
42+
SIGTERM: () => forwardSignal('SIGTERM')
43+
}
44+
45+
for (const [signal, handler] of Object.entries(signalHandlers))
46+
process.on(signal, handler)
3947

4048
/**
4149
* Determines which tool wrapper is executing.
@@ -126,8 +134,19 @@ function selectBinaryPath() {
126134
}
127135

128136
/**
129-
* Kills the child process.
137+
* Forwards a received signal to the child process, then re-emits it locally to
138+
* preserve Node.js default exit semantics.
139+
* @param {'SIGINT' | 'SIGTERM'} signal
130140
*/
131-
function killChild() {
132-
child.kill()
141+
function forwardSignal(signal) {
142+
try {
143+
if (!child.killed)
144+
child.kill(signal)
145+
} catch (error) {
146+
if (!error || error.code !== 'ESRCH')
147+
throw error
148+
}
149+
150+
process.off(signal, signalHandlers[signal])
151+
process.kill(process.pid, signal)
133152
}

0 commit comments

Comments
 (0)