Skip to content

Commit

Permalink
chore(examples): graceful-shutdown
Browse files Browse the repository at this point in the history
  • Loading branch information
fundon committed Sep 18, 2023
1 parent 6a81418 commit b40b932
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ members = [
"examples/compression",
"examples/templates/*",
"examples/tracing",
"examples/graceful-shutdown",
]
resolver = "2"

Expand Down
10 changes: 10 additions & 0 deletions examples/graceful-shutdown/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "graceful-shutdown"
version = "0.1.0"
edition.workspace = true
publish = false

[dependencies]
viz.workspace = true

tokio = { workspace = true, features = [ "rt-multi-thread", "macros" ] }
69 changes: 69 additions & 0 deletions examples/graceful-shutdown/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#![deny(warnings)]
#![allow(clippy::unused_async)]

//! Graceful shutdown server.
//!
//! See https://github.com/hyperium/hyper/blob/master/examples/graceful_shutdown.rs

use std::{net::SocketAddr, sync::Arc, time::Duration};
use tokio::{net::TcpListener, pin};
use viz::{server::conn::http1, Io, Request, Responder, Result, Router, Tree};

async fn index(_: Request) -> Result<&'static str> {
Ok("Hello, World!")
}

#[tokio::main]
async fn main() -> Result<()> {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let listener = TcpListener::bind(addr).await?;
println!("listening on {addr}");

let app = Router::new().get("/", index);
let tree = Arc::new(Tree::from(app));

// Use a 5 second timeout for incoming connections to the server.
// If a request is in progress when the 5 second timeout elapses,
// use a 2 second timeout for processing the final request and graceful shutdown.
let connection_timeouts = vec![Duration::from_secs(5), Duration::from_secs(2)];

loop {
// Clone the connection_timeouts so they can be passed to the new task.
let connection_timeouts_clone = connection_timeouts.clone();

let (stream, addr) = listener.accept().await?;
let tree = tree.clone();

tokio::task::spawn(async move {
// Pin the connection object so we can use tokio::select! below.
let conn = http1::Builder::new()
.serve_connection(Io::new(stream), Responder::new(tree, Some(addr)));
pin!(conn);

// Iterate the timeouts. Use tokio::select! to wait on the
// result of polling the connection itself,
// and also on tokio::time::sleep for the current timeout duration.
for (iter, sleep_duration) in connection_timeouts_clone.iter().enumerate() {
println!("iter = {} sleep_duration = {:?}", iter, sleep_duration);
tokio::select! {
res = conn.as_mut() => {
// Polling the connection returned a result.
// In this case print either the successful or error result for the connection
// and break out of the loop.
match res {
Ok(()) => println!("after polling conn, no error"),
Err(e) => println!("error serving connection: {:?}", e),
};
break;
}
_ = tokio::time::sleep(*sleep_duration) => {
// tokio::time::sleep returned a result.
// Call graceful_shutdown on the connection and continue the loop.
println!("iter = {} got timeout_interval, calling conn.graceful_shutdown", iter);
conn.as_mut().graceful_shutdown();
}
}
}
});
}
}

0 comments on commit b40b932

Please sign in to comment.