From e41847a378ff9bd3155ced6e00220fe9783cda1d Mon Sep 17 00:00:00 2001 From: John Nunley Date: Sun, 19 Mar 2023 06:44:10 -0700 Subject: [PATCH] ex: Add example for timed out process (#38) --- Cargo.toml | 3 ++ examples/timeout.rs | 80 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 examples/timeout.rs diff --git a/Cargo.toml b/Cargo.toml index 7243a27..f8e89e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,3 +43,6 @@ features = [ "Win32_System_Threading", "Win32_System_WindowsProgramming" ] + +[dev-dependencies] +async-io = "1.8" diff --git a/examples/timeout.rs b/examples/timeout.rs new file mode 100644 index 0000000..0706815 --- /dev/null +++ b/examples/timeout.rs @@ -0,0 +1,80 @@ +//! An example of running a `Command` with a timeout. + +use async_io::Timer; +use async_process::{Command, Stdio}; +use futures_lite::{future, prelude::*}; +use std::io; + +fn main() -> io::Result<()> { + async_io::block_on(async { + // Spawn a a command of your choice. + let mut child = Command::new("sleep") + .arg("3") + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn()?; + + // Run a future to drain the stdout of the child. + // We can't use output() here because it would be cancelled along with the child when the timeout + // expires. + let mut stdout = String::new(); + let drain_stdout = { + let buffer = &mut stdout; + let mut stdout = child.stdout.take().unwrap(); + + async move { + stdout.read_to_string(buffer).await?; + + // Wait for the child to exit or the timeout. + future::pending().await + } + }; + + // Run a future to drain the stderr of the child. + let mut stderr = String::new(); + let drain_stderr = { + let buffer = &mut stderr; + let mut stderr = child.stderr.take().unwrap(); + + async move { + stderr.read_to_string(buffer).await?; + + // Wait for the child to exit or the timeout. + future::pending().await + } + }; + + // Run a future that waits for the child to exit. + let wait = async move { + child.status().await?; + + // Child exited. + io::Result::Ok(false) + }; + + // Run a future that times out after 5 seconds. + let timeout_s = 1; + let timeout = async move { + Timer::after(std::time::Duration::from_secs(timeout_s)).await; + + // Timed out. + Ok(true) + }; + + // Run the futures concurrently. + // Note: For larger scale programs than this you should probably spawn each individual future on + // a separate task in an executor. + let timed_out = drain_stdout.or(drain_stderr).or(wait).or(timeout).await?; + + if timed_out { + println!("The child timed out."); + } else { + println!("The child exited."); + } + + println!("Stdout:\n{}", stdout); + println!("Stderr:\n{}", stderr); + + Ok(()) + }) +}