refactor: proper SIGTERM, SIGINT and SIGQUIT handling
Diff
Cargo.lock | 27 +++++++++++++++++++++++++--
Cargo.toml | 4 +++-
src/server.rs | 17 ++++++++++++-----
src/signals.rs | 34 +++++++++++++++++++++++++++-------
4 files changed, 67 insertions(+), 15 deletions(-)
@@ -822,6 +822,17 @@ dependencies = [
]
[[package]]
name = "signal-hook"
version = "0.3.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c98891d737e271a2954825ef19e46bd16bdb98e2746f2eec4f7a4ef7946efd1"
dependencies = [
"cc",
"libc",
"signal-hook-registry",
]
[[package]]
name = "signal-hook-registry"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -831,6 +842,18 @@ dependencies = [
]
[[package]]
name = "signal-hook-tokio"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6c5d32165ff8b94e68e7b3bdecb1b082e958c22434b363482cfb89dcd6f3ff8"
dependencies = [
"futures-core",
"libc",
"signal-hook",
"tokio",
]
[[package]]
name = "slab"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -877,6 +900,8 @@ dependencies = [
"num_cpus",
"percent-encoding",
"pin-project",
"signal-hook",
"signal-hook-tokio",
"structopt",
"time",
"tokio",
@@ -961,9 +986,7 @@ dependencies = [
"memchr",
"mio",
"num_cpus",
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"tokio-macros",
"winapi",
]
@@ -44,11 +44,13 @@ percent-encoding = "2.1"
pin-project = "1.0"
structopt = { version = "0.3", default-features = false }
time = "0.1"
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"], default-features = false }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util"], default-features = false }
tokio-rustls = { version = "0.22" }
tokio-util = { version = "0.6", features = ["io"] }
tracing = "0.1"
tracing-subscriber = "0.2"
signal-hook = { version = "0.3.4", features = ["extended-siginfo"] }
signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"], default-features = false }
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
version = "0.3"
@@ -156,9 +156,12 @@ impl Server {
"error during TLS server initialization, probably cert or key file missing",
);
let signals = signals::create_signals()?;
let handle = signals.handle();
let server = HyperServer::builder(TlsAcceptor::new(tls, incoming))
.serve(router_service)
.with_graceful_shutdown(signals::wait_for_ctrl_c());
.with_graceful_shutdown(signals::wait_for_signals(signals));
tracing::info!(
parent: tracing::info_span!("Server::start_server", ?addr_str, ?threads),
@@ -166,17 +169,20 @@ impl Server {
addr_str
);
tracing::info!("press Ctrl + C to shut down the server");
tracing::info!("press ctrl+c to shut down the server");
server.await?;
handle.close();
} else {
let signals = signals::create_signals()?;
let handle = signals.handle();
let server = HyperServer::from_tcp(tcp_listener)
.unwrap()
.tcp_nodelay(true)
.serve(router_service)
.with_graceful_shutdown(signals::wait_for_ctrl_c());
.with_graceful_shutdown(signals::wait_for_signals(signals));
tracing::info!(
parent: tracing::info_span!("Server::start_server", ?addr_str, ?threads),
@@ -184,12 +190,13 @@ impl Server {
addr_str
);
tracing::info!("press Ctrl + C to shut down the server");
tracing::info!("press ctrl+c to shut down the server");
server.await?;
handle.close();
}
tracing::warn!("Ctrl+C signal caught, shutting down the server execution");
tracing::warn!("termination signal caught, shutting down the server execution");
Ok(())
}
@@ -1,8 +1,28 @@
pub async fn wait_for_ctrl_c() {
tracing::debug!("server waiting for incoming Ctrl+C signals");
tokio::signal::ctrl_c()
.await
.expect("failed to install the Ctrl+C signal handler");
tracing::debug!("server caught an incoming Ctrl+C signal, starting graceful shutdown");
use futures_util::stream::StreamExt;
use signal_hook::consts::signal::*;
use signal_hook_tokio::Signals;
use crate::Result;
pub fn create_signals() -> Result<Signals> {
Ok(Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT])?)
}
pub async fn wait_for_signals(signals: Signals) {
let mut signals = signals.fuse();
while let Some(signal) = signals.next().await {
match signal {
SIGHUP => {
tracing::debug!("SIGHUP caught, nothing to do about")
}
SIGTERM | SIGINT | SIGQUIT => {
tracing::debug!("an incoming SIGTERM received, SIGINT or SIGQUIT signal, delegating graceful shutdown to server");
break;
}
_ => unreachable!(),
}
}
}