Home > Net >  Letting a parent Rust process terminate without waiting for a subprocess
Letting a parent Rust process terminate without waiting for a subprocess

Time:09-17

I have a Rust process that is supposed to launch a subprocess and then immediately exit. This appears to work:

fn main() {
    // Intentionally drop the returned Child and exit
    Command::new("bash").args(&["-c", "sleep 10s; touch done"]).spawn().unwrap();
}

Running this process exits immediately and the bash process continues:

$ cargo build; target/debug/demo

$ ps aux | grep bash
dimo414         35959   0.0  0.0  4278616   1484 s001  S     1:12PM   0:00.00 bash -c sleep 10s; touch done
...

However if I add one more layer and try to invoke my binary and await its completion that also appears to wait for the subprocess, unlike what I observe in the shell. Here's an MCVE:

fn main() {
    let exec = std::env::current_exe().expect("Could not resolve executable location");
    // First re-invoke the same binary and await it
    if std::env::args().len() < 2 {
        println!("Ran Subprocess:\n{:?}", Command::new(exec).arg("").output().unwrap());
    } else {
        // In that subprocess spawn a long-running process but don't wait
        println!("Spawning Subprocess");
        Command::new("bash").args(&["-c", "sleep 10s; touch done"]).spawn().unwrap();
    }
}
$ cargo build; target/debug/demo
# doesn't terminate until the bash process does

Is there a way to allow the top-level process to complete without waiting for the nested process?

CodePudding user response:

Please check the reference of spawn

Executes the command as a child process, returning a handle to it.

By default, stdin, stdout and stderr are inherited from the parent.

When you run self as a subprocess it spawns another subprocess with inheriting stdio from parent. Since your top-level process uses output() it will wait subprocess to finish and collect its all output (reference).

Let's demonstrate it like this:

Root -> Sub1 -> Sub2

Sub2 uses stdout channel of Sub1, Root waits to collect all output from Sub1 which is still in use by Sub2, at the end of the day Root waits for Sub2 to finish.

Solution is; simply use Stdio::null() to send output to /dev/null since your Root process does not care about the output of Sub2.

fn main() {
    let exec = std::env::current_exe().expect("Could not resolve executable location");
    if std::env::args().len() < 2 {
        println!(
            "Ran Subprocess:\n{:?}",
            Command::new(exec).arg("").output().unwrap()
        );
    } else {
        println!("Spawning Subprocess");
        Command::new("bash")
            .stdout(Stdio::null())
            .stderr(Stdio::null())
            .args(&["-c", "sleep 10s; touch done"])
            .spawn()
            .unwrap();
    }
}
  • Related