File: timeout.rs

package info (click to toggle)
rust-async-process 2.4.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 248 kB
  • sloc: makefile: 2; sh: 1
file content (80 lines) | stat: -rw-r--r-- 2,398 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
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 1 second.
        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(())
    })
}