refactor: explicit `ctrl+c` signal handling for windows
it preserves `graceful shutdown` but via `ctrl+c`
Diff
Cargo.lock | 2 ++
Cargo.toml | 2 +-
src/server.rs | 27 ++++++++++++++++++++++-----
src/signals.rs | 26 +++++++++++---------------
4 files changed, 36 insertions(+), 21 deletions(-)
@@ -986,7 +986,9 @@ dependencies = [
"memchr",
"mio",
"num_cpus",
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"tokio-macros",
"winapi",
]
@@ -44,7 +44,7 @@ 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"], default-features = false }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util", "signal"], default-features = false }
tokio-rustls = { version = "0.22" }
tokio-util = { version = "0.6", features = ["io"] }
tracing = "0.1"
@@ -156,12 +156,18 @@ impl Server {
"error during TLS server initialization, probably cert or key file missing",
);
#[cfg(not(windows))]
let signals = signals::create_signals()?;
#[cfg(not(windows))]
let handle = signals.handle();
let server = HyperServer::builder(TlsAcceptor::new(tls, incoming))
.serve(router_service)
.with_graceful_shutdown(signals::wait_for_signals(signals));
let server =
HyperServer::builder(TlsAcceptor::new(tls, incoming)).serve(router_service);
#[cfg(not(windows))]
let server = server.with_graceful_shutdown(signals::wait_for_signals(signals));
#[cfg(windows)]
let server = server.with_graceful_shutdown(signals::wait_for_ctrl_c());
tracing::info!(
parent: tracing::info_span!("Server::start_server", ?addr_str, ?threads),
@@ -172,17 +178,26 @@ impl Server {
tracing::info!("press ctrl+c to shut down the server");
server.await?;
#[cfg(not(windows))]
handle.close();
} else {
#[cfg(not(windows))]
let signals = signals::create_signals()?;
#[cfg(not(windows))]
let handle = signals.handle();
let server = HyperServer::from_tcp(tcp_listener)
.unwrap()
.tcp_nodelay(true)
.serve(router_service)
.with_graceful_shutdown(signals::wait_for_signals(signals));
.serve(router_service);
#[cfg(not(windows))]
let server = server.with_graceful_shutdown(signals::wait_for_signals(signals));
#[cfg(windows)]
let server = server.with_graceful_shutdown(signals::wait_for_ctrl_c());
tracing::info!(
parent: tracing::info_span!("Server::start_server", ?addr_str, ?threads),
@@ -193,6 +208,8 @@ impl Server {
tracing::info!("press ctrl+c to shut down the server");
server.await?;
#[cfg(not(windows))]
handle.close();
}
@@ -1,10 +1,8 @@
#[cfg(not(windows))]
use {futures_util::stream::StreamExt, signal_hook::consts::signal::*, signal_hook_tokio::Signals};
#[cfg(windows)]
type Signals = futures_util::stream::Empty<()>;
use crate::Result;
use {
crate::Result, futures_util::stream::StreamExt, signal_hook::consts::signal::*,
signal_hook_tokio::Signals,
};
#[cfg(not(windows))]
@@ -12,14 +10,8 @@ pub fn create_signals() -> Result<Signals> {
Ok(Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT])?)
}
#[cfg(windows)]
pub fn create_signals() -> Result<Signals> {
Ok(futures_util::stream::empty())
}
#[cfg(not(windows))]
pub async fn wait_for_signals(signals: Signals) {
let mut signals = signals.fuse();
while let Some(signal) = signals.next().await {
@@ -38,5 +30,9 @@ pub async fn wait_for_signals(signals: Signals) {
}
#[cfg(windows)]
pub async fn wait_for_signals(signals: Signals) {}
pub async fn wait_for_ctrl_c() {
tokio::signal::ctrl_c()
.await
.expect("failed to install ctrl+c signal handler");
}