Skip to main content

run_cmd_in_with_timeout

Function run_cmd_in_with_timeout 

Source
pub fn run_cmd_in_with_timeout(
    dir: &Path,
    program: &str,
    args: &[&str],
    timeout: Duration,
) -> Result<RunOutput, RunError>
Expand description

Run a command in a directory, killing it if it exceeds timeout.

Uses background threads to drain stdout and stderr so a chatty process can’t block on pipe buffer overflow. On timeout, the child is killed and any output collected before the kill is included in the error.

Returns RunError::Timeout if the process was killed. Returns RunError::NonZeroExit if it completed with a non-zero status. Returns RunError::Spawn if the process couldn’t start.

§Caveat: grandchildren

Only the direct child process receives the kill signal. Grandchildren (spawned by the child) become orphans and continue running, and they may hold the stdout/stderr pipes open, delaying this function’s return until they exit naturally. This is rare for direct invocations of git/jj but can matter for shell wrappers — use exec in the shell command (e.g., sh -c "exec git fetch") to replace the shell with the target process and avoid the grandchild case.

let repo = Path::new("/repo");
match run_cmd_in_with_timeout(repo, "git", &["fetch"], Duration::from_secs(30)) {
    Ok(_) => println!("fetched"),
    Err(RunError::Timeout { elapsed, .. }) => {
        eprintln!("fetch hung, killed after {elapsed:?}");
    }
    Err(e) => return Err(e.into()),
}