-
-
Notifications
You must be signed in to change notification settings - Fork 134
/
app.rs
118 lines (102 loc) · 3.18 KB
/
app.rs
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
use std::{sync::Arc, time::Duration};
static HELP: &str = r#"
Example console-instrumented app
USAGE:
app [OPTIONS]
OPTIONS:
-h, help prints this message
blocks Includes a (misbehaving) blocking task
burn Includes a (misbehaving) task that spins CPU with self-wakes
coma Includes a (misbehaving) task that forgets to register a waker
"#;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
use tracing_subscriber::prelude::*;
// initialize an underlying `Registry`
let registry = Arc::new(tracing_subscriber::registry());
// spawn the console server in the background,
// returning a `Layer`:
let console_layer = console_subscriber::spawn(registry.clone());
// build a `Subscriber` by combining layers with the
// `registry`:
registry.with(console_layer).init();
// spawn optional extras from CLI args
// skip first which is command name
for opt in std::env::args().skip(1) {
match &*opt {
"blocks" => {
tokio::task::Builder::new()
.name("blocks")
.spawn(double_sleepy(1, 10));
}
"coma" => {
tokio::task::Builder::new()
.name("coma")
.spawn(std::future::pending::<()>());
}
"burn" => {
tokio::task::Builder::new().name("burn").spawn(burn(1, 10));
}
"help" | "-h" => {
eprintln!("{}", HELP);
return Ok(());
}
wat => {
return Err(
format!("unknown option: {:?}, run with '-h' to see options", wat).into(),
)
}
}
}
let task1 = tokio::task::Builder::new()
.name("task1")
.spawn(spawn_tasks(1, 10));
let task2 = tokio::task::Builder::new()
.name("task2")
.spawn(spawn_tasks(10, 30));
let result = tokio::try_join! {
task1,
task2,
};
result?;
Ok(())
}
#[tracing::instrument]
async fn spawn_tasks(min: u64, max: u64) {
loop {
for i in min..max {
tracing::trace!(i, "spawning wait task");
tokio::task::Builder::new().name("wait").spawn(wait(i));
let sleep = Duration::from_secs(max) - Duration::from_secs(i);
tracing::trace!(?sleep, "sleeping...");
tokio::time::sleep(sleep).await;
}
}
}
#[tracing::instrument]
async fn wait(seconds: u64) {
tracing::debug!("waiting...");
tokio::time::sleep(Duration::from_secs(seconds)).await;
tracing::trace!("done!");
}
#[tracing::instrument]
async fn double_sleepy(min: u64, max: u64) {
loop {
for i in min..max {
// woops!
std::thread::sleep(Duration::from_secs(i));
tokio::time::sleep(Duration::from_secs(max - i)).await;
}
}
}
#[tracing::instrument]
async fn burn(min: u64, max: u64) {
loop {
for i in min..max {
for _ in 0..i {
tokio::task::yield_now().await;
}
tokio::time::sleep(Duration::from_secs(i - min)).await;
}
}
}