Skip to content

Commit 86557b2

Browse files
committed
🤖 Add remote-side timeout using timeout command
When SSH is killed locally, the remote command may continue running (especially with ControlMaster multiplexing). Wrap remote commands with the `timeout` utility to ensure they're killed on the remote side too. Uses SIGKILL and sets remote timeout slightly longer than local timeout to ensure the local timeout normally fires first.
1 parent c16b17b commit 86557b2

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

src/runtime/SSHRuntime.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,23 @@ export class SSHRuntime implements Runtime {
9191
parts.push(command);
9292

9393
// Join all parts with && to ensure each step succeeds before continuing
94-
const fullCommand = parts.join(" && ");
94+
let fullCommand = parts.join(" && ");
95+
96+
// Wrap command with timeout if specified
97+
// This ensures the remote command is killed even if the SSH connection persists
98+
// (e.g., due to ControlMaster multiplexing)
99+
if (options.timeout !== undefined) {
100+
// Use timeout command with KILL signal after timeout expires
101+
// The timeout value is slightly longer than our local timeout to ensure
102+
// the local timeout fires first in normal cases
103+
const remoteTimeout = Math.ceil(options.timeout) + 1;
104+
fullCommand = `timeout --signal=KILL ${remoteTimeout} bash -c ${shescape.quote(fullCommand)}`;
105+
}
95106

96107
// Wrap in bash -c with shescape for safe shell execution
97-
const remoteCommand = `bash -c ${shescape.quote(fullCommand)}`;
108+
const remoteCommand = options.timeout
109+
? fullCommand
110+
: `bash -c ${shescape.quote(fullCommand)}`;
98111

99112
// Build SSH args
100113
const sshArgs: string[] = ["-T"];

0 commit comments

Comments
 (0)