Skip to main content

timeout/
timeout.rs

1//! An example of running a `Command` with a timeout.
2
3use async_io::Timer;
4use async_process::{Command, Stdio};
5use futures_lite::{future, prelude::*};
6use std::io;
7
8fn main() -> io::Result<()> {
9    async_io::block_on(async {
10        // Spawn a a command of your choice.
11        let mut child = Command::new("sleep")
12            .arg("3")
13            .stdout(Stdio::piped())
14            .stderr(Stdio::piped())
15            .spawn()?;
16
17        // Run a future to drain the stdout of the child.
18        // We can't use output() here because it would be cancelled along with the child when the timeout
19        // expires.
20        let mut stdout = String::new();
21        let drain_stdout = {
22            let buffer = &mut stdout;
23            let mut stdout = child.stdout.take().unwrap();
24
25            async move {
26                stdout.read_to_string(buffer).await?;
27
28                // Wait for the child to exit or the timeout.
29                future::pending().await
30            }
31        };
32
33        // Run a future to drain the stderr of the child.
34        let mut stderr = String::new();
35        let drain_stderr = {
36            let buffer = &mut stderr;
37            let mut stderr = child.stderr.take().unwrap();
38
39            async move {
40                stderr.read_to_string(buffer).await?;
41
42                // Wait for the child to exit or the timeout.
43                future::pending().await
44            }
45        };
46
47        // Run a future that waits for the child to exit.
48        let wait = async move {
49            child.status().await?;
50
51            // Child exited.
52            io::Result::Ok(false)
53        };
54
55        // Run a future that times out after 1 second.
56        let timeout_s = 1;
57        let timeout = async move {
58            Timer::after(std::time::Duration::from_secs(timeout_s)).await;
59
60            // Timed out.
61            Ok(true)
62        };
63
64        // Run the futures concurrently.
65        // Note: For larger scale programs than this you should probably spawn each individual future on
66        // a separate task in an executor.
67        let timed_out = drain_stdout.or(drain_stderr).or(wait).or(timeout).await?;
68
69        if timed_out {
70            println!("The child timed out.");
71        } else {
72            println!("The child exited.");
73        }
74
75        println!("Stdout:\n{stdout}");
76        println!("Stderr:\n{stderr}");
77
78        Ok(())
79    })
80}