Skip to content

Commit ed8dcf4

Browse files
committed
fix: address review comments for kill button PR
- Use promise instead of setTimeout to avoid race condition - Add validation for parseInt to handle NaN cases - Fix setActiveStream to use updated PID instead of subprocess.pid - Clear subprocess reference in error cases - Add logging for kill operation failures
1 parent 7620277 commit ed8dcf4

File tree

1 file changed

+47
-23
lines changed

1 file changed

+47
-23
lines changed

src/integrations/terminal/ExecaTerminalProcess.ts

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
1010
private aborted = false
1111
private pid?: number
1212
private subprocess?: ReturnType<typeof execa>
13+
private pidUpdatePromise?: Promise<void>
1314

1415
constructor(terminal: RooTerminal) {
1516
super()
@@ -54,15 +55,20 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
5455
// When using shell: true, the PID is for the shell, not the actual command
5556
// Find the actual command PID after a small delay
5657
if (this.pid) {
57-
setTimeout(() => {
58-
psTree(this.pid!, (err, children) => {
59-
if (!err && children.length > 0) {
60-
// Update PID to the first child (the actual command)
61-
const actualPid = parseInt(children[0].PID)
62-
this.pid = actualPid
63-
}
64-
})
65-
}, 100)
58+
this.pidUpdatePromise = new Promise<void>((resolve) => {
59+
setTimeout(() => {
60+
psTree(this.pid!, (err, children) => {
61+
if (!err && children.length > 0) {
62+
// Update PID to the first child (the actual command)
63+
const actualPid = parseInt(children[0].PID)
64+
if (!isNaN(actualPid)) {
65+
this.pid = actualPid
66+
}
67+
}
68+
resolve()
69+
})
70+
}, 100)
71+
})
6672
}
6773

6874
const rawStream = this.subprocess.iterable({ from: "all", preserveNewlines: true })
@@ -74,7 +80,7 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
7480
}
7581
})()
7682

77-
this.terminal.setActiveStream(stream, this.subprocess.pid)
83+
this.terminal.setActiveStream(stream, this.pid)
7884

7985
for await (const line of stream) {
8086
if (this.aborted) {
@@ -133,6 +139,7 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
133139

134140
this.emit("shell_execution_complete", { exitCode: 1 })
135141
}
142+
this.subprocess = undefined
136143
}
137144

138145
this.terminal.setActiveStream(undefined)
@@ -152,23 +159,40 @@ export class ExecaTerminalProcess extends BaseTerminalProcess {
152159
public override abort() {
153160
this.aborted = true
154161

155-
// Try to kill using the subprocess object
156-
if (this.subprocess) {
157-
try {
158-
this.subprocess.kill("SIGKILL")
159-
} catch (e) {
160-
// Ignore errors, will try direct kill below
162+
// Function to perform the kill operations
163+
const performKill = () => {
164+
// Try to kill using the subprocess object
165+
if (this.subprocess) {
166+
try {
167+
this.subprocess.kill("SIGKILL")
168+
} catch (e) {
169+
console.warn(
170+
`[ExecaTerminalProcess#abort] Failed to kill subprocess: ${e instanceof Error ? e.message : String(e)}`,
171+
)
172+
}
161173
}
162-
}
163174

164-
// Kill the stored PID (which should be the actual command after our update)
165-
if (this.pid) {
166-
try {
167-
process.kill(this.pid, "SIGKILL")
168-
} catch (e) {
169-
// Process might already be dead
175+
// Kill the stored PID (which should be the actual command after our update)
176+
if (this.pid) {
177+
try {
178+
process.kill(this.pid, "SIGKILL")
179+
} catch (e) {
180+
console.warn(
181+
`[ExecaTerminalProcess#abort] Failed to kill process ${this.pid}: ${e instanceof Error ? e.message : String(e)}`,
182+
)
183+
}
170184
}
185+
}
171186

187+
// If PID update is in progress, wait for it before killing
188+
if (this.pidUpdatePromise) {
189+
this.pidUpdatePromise.then(performKill).catch(() => performKill())
190+
} else {
191+
performKill()
192+
}
193+
194+
// Continue with the rest of the abort logic
195+
if (this.pid) {
172196
// Also check for any child processes
173197
psTree(this.pid, async (err, children) => {
174198
if (!err) {

0 commit comments

Comments
 (0)