Skip to content

Commit f6827ca

Browse files
committed
temp
1 parent bfca546 commit f6827ca

File tree

1 file changed

+104
-0
lines changed

1 file changed

+104
-0
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//! This example demonstrates the configurable shutdown timeout feature of the non-blocking writer.
2+
//!
3+
//! The example uses a custom blocking writer that can simulate slow I/O operations,
4+
//! allowing us to see how the timeout behaves when the worker thread is blocked
5+
//! during shutdown.
6+
7+
use std::{io::{self, Write}, thread, time::{Duration, Instant}};
8+
use tracing::info;
9+
use tracing_appender::non_blocking::NonBlockingBuilder;
10+
11+
static BLOCK_IN_WORKER: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
12+
static BLOCK_DURATION_SECS: std::sync::atomic::AtomicU64 = std::sync::atomic::AtomicU64::new(3);
13+
14+
struct BlockingMemoryWriter{
15+
buffer: Vec<u8>,
16+
}
17+
18+
impl BlockingMemoryWriter {
19+
fn new() -> Self {
20+
Self {
21+
buffer: Vec::new()
22+
}
23+
}
24+
25+
fn contents(&self) -> String {
26+
String::from_utf8_lossy(&self.buffer).to_string()
27+
}
28+
}
29+
30+
impl Write for BlockingMemoryWriter {
31+
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
32+
if BLOCK_IN_WORKER.load(std::sync::atomic::Ordering::Relaxed) {
33+
let block_secs = BLOCK_DURATION_SECS.load(std::sync::atomic::Ordering::Relaxed);
34+
println!("Blocking in write() for {} seconds...", block_secs);
35+
thread::sleep(Duration::from_secs(block_secs));
36+
println!("Done blocking in write()");
37+
}
38+
self.buffer.extend_from_slice(buf);
39+
Ok(buf.len())
40+
}
41+
42+
fn flush(&mut self) -> io::Result<()> {
43+
self.buffer.flush()
44+
}
45+
}
46+
47+
impl Drop for BlockingMemoryWriter {
48+
fn drop(&mut self) {
49+
println!("BlockingMemoryWriter dropped. Final contents:");
50+
println!("{}", self.contents());
51+
}
52+
}
53+
54+
fn main() {
55+
let block_secs = 2;
56+
let shutdown_timeout = Duration::from_millis(300);
57+
58+
BLOCK_DURATION_SECS.store(block_secs, std::sync::atomic::Ordering::Relaxed);
59+
println!("Blocking for {} seconds in main thread", block_secs);
60+
println!("Shutdown timeout set to {:?}", shutdown_timeout);
61+
62+
let blocking_writer = BlockingMemoryWriter::new();
63+
64+
let (non_blocking, guard) = NonBlockingBuilder::default()
65+
.shutdown_timeout(shutdown_timeout)
66+
.finish(blocking_writer);
67+
68+
tracing_subscriber::fmt()
69+
.with_writer(non_blocking)
70+
.init();
71+
72+
for i in 0..5 {
73+
info!("Log message {}", i);
74+
}
75+
76+
thread::sleep(Duration::from_millis(100));
77+
78+
println!("\n=== BLOCKING IN WORKER THREAD ===");
79+
BLOCK_IN_WORKER.store(true, std::sync::atomic::Ordering::Relaxed);
80+
info!("This message will cause blocking in the worker thread");
81+
thread::sleep(Duration::from_millis(100));
82+
83+
println!("\n=== STARTING SHUTDOWN (should take ~1 second due to timeout) ===");
84+
let shutdown_start = Instant::now();
85+
86+
drop(guard);
87+
88+
let shutdown_duration = shutdown_start.elapsed();
89+
println!("=== SHUTDOWN COMPLETED in {:?} ===", shutdown_duration);
90+
91+
let expected_min = shutdown_timeout.as_millis() * 9 / 10;
92+
let expected_max = shutdown_timeout.as_millis() * 11 / 10;
93+
94+
if shutdown_duration.as_millis() > expected_min && shutdown_duration.as_millis() < expected_max {
95+
println!("Shutdown took ~{:?} second as expected", shutdown_timeout);
96+
} else {
97+
println!("Shutdown took {:?} instead of ~{:?} second", shutdown_duration, shutdown_timeout);
98+
}
99+
100+
println!("\n=== WAITING TO SEE BACKGROUND THREAD FINISH ===");
101+
thread::sleep(Duration::from_secs(block_secs + 1));
102+
println!("=== MAIN THREAD EXITING ===");
103+
104+
}

0 commit comments

Comments
 (0)