pub fn spawn(
        &self,
        command: Command,
        stop_timeout: Duration,
    ) -> Option<io::Result<child::Child>> {
        let label = tracing::enabled!(tracing::Level::TRACE)
            .then(|| command.label())
            .unwrap_or_default();
        trace!("acquiring lock for spawning {label}");
        let mut lock = self.state.lock().unwrap();
        trace!("acquired lock for spawning {label}");
        if lock.is_closing {
            debug!("process manager closing");
            return None;
        }
        let pty_size = self.use_pty.then(|| lock.pty_size()).flatten();
        let child = child::Child::spawn(
            command,
            child::ShutdownStyle::Graceful(stop_timeout),
            pty_size,
        );
        if let Ok(child) = &child {
            lock.children.push(child.clone());
        }
        trace!("releasing lock for spawning {label}");
        Some(child)
    }
Spawn a new child process to run the given command.

The handle of the child can be either waited or stopped by the caller,
as well as the entire process manager.

If spawn returns None, the process manager is closed and the child
process was not spawned. If spawn returns Some(Err), the process
manager is open, but the child process failed to spawn.
crates/turborepo-process/src/lib.rs