index : static-web-server.git

ascending towards madness

author Jose Quintana <joseluisquintana20@gmail.com> 2021-10-29 22:46:53.0 +00:00:00
committer Jose Quintana <joseluisquintana20@gmail.com> 2021-10-29 22:46:53.0 +00:00:00
commit
c16e7d50e5e0623d19be2621c4ab78d2db1023f6 [patch]
tree
ab5587ceffc99b34e662c6fca311ff77e4fa2dc4
parent
1457915cda8da85c2f4b46f7585c25135fdeeece
download
c16e7d50e5e0623d19be2621c4ab78d2db1023f6.tar.gz

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(-)

diff --git a/Cargo.lock b/Cargo.lock
index ac8840e..0d0b2f4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -986,7 +986,9 @@ dependencies = [
 "memchr",
 "mio",
 "num_cpus",
 "once_cell",
 "pin-project-lite",
 "signal-hook-registry",
 "tokio-macros",
 "winapi",
]
diff --git a/Cargo.toml b/Cargo.toml
index 5dd381b..273dbba 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/src/server.rs b/src/server.rs
index 7b268ec..191b3eb 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -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 {
            // HTTP/1

            #[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();
        }

diff --git a/src/signals.rs b/src/signals.rs
index 2cbc9f8..20fc4da 100644
--- a/src/signals.rs
+++ b/src/signals.rs
@@ -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))]
/// It creates a common list of signals stream for `SIGTERM`, `SIGINT` and `SIGQUIT` to be observed.
@@ -12,14 +10,8 @@ pub fn create_signals() -> Result<Signals> {
    Ok(Signals::new(&[SIGHUP, SIGTERM, SIGINT, SIGQUIT])?)
}

#[cfg(windows)]
// No signal handling available on Windows for now
pub fn create_signals() -> Result<Signals> {
    Ok(futures_util::stream::empty())
}

#[cfg(not(windows))]
/// It waits for a specific type of incoming signals.
/// It waits for a specific type of incoming signals included `ctrl+c`.
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)]
// No signal handling available on Windows for now
pub async fn wait_for_signals(signals: Signals) {}
/// It waits for an incoming `ctrl+c` signal on Windows.
pub async fn wait_for_ctrl_c() {
    tokio::signal::ctrl_c()
        .await
        .expect("failed to install ctrl+c signal handler");
}