Skip to content

Commit bb5c148

Browse files
seanmonstarglendc
and
glendc
authored
feat: add GracefulShutdown helper (#127)
Co-authored-by: glendc <glen.decauwsemaecker@otainsight.com>
1 parent 97714e5 commit bb5c148

File tree

4 files changed

+524
-1
lines changed

4 files changed

+524
-1
lines changed

Cargo.toml

+7-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ tower = { version = "0.4.1", optional = true, default-features = false, features
3535
hyper = { version = "1.3.0", features = ["full"] }
3636
bytes = "1"
3737
http-body-util = "0.1.0"
38-
tokio = { version = "1", features = ["macros", "test-util"] }
38+
tokio = { version = "1", features = ["macros", "test-util", "signal"] }
3939
tokio-test = "0.4"
4040
pretty_env_logger = "0.5"
4141

@@ -51,6 +51,7 @@ full = [
5151
"client-legacy",
5252
"server",
5353
"server-auto",
54+
"server-graceful",
5455
"service",
5556
"http1",
5657
"http2",
@@ -62,6 +63,7 @@ client-legacy = ["client", "dep:socket2", "tokio/sync"]
6263

6364
server = ["hyper/server"]
6465
server-auto = ["server", "http1", "http2"]
66+
server-graceful = ["server", "tokio/sync"]
6567

6668
service = ["dep:tower", "dep:tower-service"]
6769

@@ -80,3 +82,7 @@ required-features = ["client-legacy", "http1", "tokio"]
8082
[[example]]
8183
name = "server"
8284
required-features = ["server", "http1", "tokio"]
85+
86+
[[example]]
87+
name = "server_graceful"
88+
required-features = ["tokio", "server-graceful", "server-auto"]

examples/server_graceful.rs

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use bytes::Bytes;
2+
use std::convert::Infallible;
3+
use std::pin::pin;
4+
use std::time::Duration;
5+
use tokio::net::TcpListener;
6+
7+
#[tokio::main(flavor = "current_thread")]
8+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
9+
let listener = TcpListener::bind("127.0.0.1:8080").await?;
10+
11+
let server = hyper_util::server::conn::auto::Builder::new(hyper_util::rt::TokioExecutor::new());
12+
let graceful = hyper_util::server::graceful::GracefulShutdown::new();
13+
let mut ctrl_c = pin!(tokio::signal::ctrl_c());
14+
15+
loop {
16+
tokio::select! {
17+
conn = listener.accept() => {
18+
let (stream, peer_addr) = match conn {
19+
Ok(conn) => conn,
20+
Err(e) => {
21+
eprintln!("accept error: {}", e);
22+
tokio::time::sleep(Duration::from_secs(1)).await;
23+
continue;
24+
}
25+
};
26+
eprintln!("incomming connection accepted: {}", peer_addr);
27+
28+
let stream = hyper_util::rt::TokioIo::new(Box::pin(stream));
29+
30+
let conn = server.serve_connection_with_upgrades(stream, hyper::service::service_fn(|_| async move {
31+
tokio::time::sleep(Duration::from_secs(5)).await; // emulate slow request
32+
let body = http_body_util::Full::<Bytes>::from("Hello World!".to_owned());
33+
Ok::<_, Infallible>(http::Response::new(body))
34+
}));
35+
36+
let conn = graceful.watch(conn.into_owned());
37+
38+
tokio::spawn(async move {
39+
if let Err(err) = conn.await {
40+
eprintln!("connection error: {}", err);
41+
}
42+
eprintln!("connection dropped: {}", peer_addr);
43+
});
44+
},
45+
46+
_ = ctrl_c.as_mut() => {
47+
drop(listener);
48+
eprintln!("Ctrl-C received, starting shutdown");
49+
break;
50+
}
51+
}
52+
}
53+
54+
tokio::select! {
55+
_ = graceful.shutdown() => {
56+
eprintln!("Gracefully shutdown!");
57+
},
58+
_ = tokio::time::sleep(Duration::from_secs(10)) => {
59+
eprintln!("Waited 10 seconds for graceful shutdown, aborting...");
60+
}
61+
}
62+
63+
Ok(())
64+
}

0 commit comments

Comments
 (0)