refactor: signals handling
Diff
Cargo.lock | 47 ++++++++++++++++++++++++++++++++++++-----------
Cargo.toml | 8 +++++++-
src/lib.rs | 1 +
src/server.rs | 58 +++++++++++++++++++++++++++++++++++-----------------------
src/signals.rs | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 130 insertions(+), 35 deletions(-)
@@ -62,6 +62,12 @@ checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
@@ -332,7 +338,7 @@ version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
]
[[package]]
@@ -389,6 +395,19 @@ dependencies = [
]
[[package]]
name = "nix"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce"
dependencies = [
"bitflags",
"cc",
"cfg-if 0.1.10",
"libc",
"void",
]
[[package]]
name = "ntapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -573,7 +592,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfebf75d25bd900fd1e7d11501efab59bc846dbc76196839663e6637bba9f25f"
dependencies = [
"block-buffer",
"cfg-if",
"cfg-if 1.0.0",
"cpuid-bool",
"digest",
"opaque-debug",
@@ -589,12 +608,13 @@ dependencies = [
]
[[package]]
name = "signal-hook-registry"
version = "1.3.0"
name = "signal"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6"
checksum = "2f6ce83b159ab6984d2419f495134972b48754d13ff2e3f8c998339942b56ed9"
dependencies = [
"libc",
"nix",
]
[[package]]
@@ -624,9 +644,11 @@ dependencies = [
"hyper",
"jemallocator",
"mime_guess",
"nix",
"num_cpus",
"once_cell",
"percent-encoding",
"signal",
"structopt",
"tokio",
"tokio-util",
@@ -710,11 +732,8 @@ dependencies = [
"memchr",
"mio",
"num_cpus",
"once_cell",
"pin-project-lite",
"signal-hook-registry",
"tokio-macros",
"winapi",
]
[[package]]
@@ -754,7 +773,7 @@ version = "0.1.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01ebdc2bb4498ab1ab5f5b73c5803825e60199229ccba0698170e3be0e7f959f"
dependencies = [
"cfg-if",
"cfg-if 1.0.0",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -858,9 +877,9 @@ checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
[[package]]
name = "unicode-xid"
version = "0.2.1"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
[[package]]
name = "version_check"
@@ -869,6 +888,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "want"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -26,7 +26,7 @@ path = "src/bin/server.rs"
[dependencies]
hyper = { version = "0.14", features = ["stream", "http1", "tcp", "server"] }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "signal", "fs", "io-util"], default-features = false }
tokio = { version = "1", features = ["rt-multi-thread", "macros", "fs", "io-util"], default-features = false }
futures = { version = "0.3", default-features = false }
headers = "0.3"
tokio-util = { version = "0.6", features = ["io"] }
@@ -40,6 +40,12 @@ structopt = { version = "0.3", default-features = false }
num_cpus = { version = "1.13" }
once_cell = "1.7"
[target.'cfg(not(windows))'.dependencies.nix]
version = "0.14"
[target.'cfg(not(windows))'.dependencies.signal]
version = "0.7"
[target.'cfg(all(target_env = "musl", target_pointer_width = "64"))'.dependencies.jemallocator]
version = "0.3"
@@ -10,6 +10,7 @@ pub mod fs;
pub mod helpers;
pub mod logger;
pub mod server;
pub mod signals;
#[macro_use]
pub mod error;
@@ -3,7 +3,6 @@ use hyper::service::{make_service_fn, service_fn};
use std::net::{IpAddr, SocketAddr};
use std::sync::Arc;
use structopt::StructOpt;
use tokio::signal;
use crate::{
config::{Config, CONFIG},
@@ -76,30 +75,26 @@ impl Server {
let span = tracing::info_span!("Server::run", ?addr, threads = ?self.threads);
tracing::info!(parent: &span, "listening on http://{}", addr);
tokio::task::spawn(async move {
let span = tracing::info_span!("Server::run", ?addr, threads = ?self.threads);
tracing::info!(parent: &span, "listening on http://{}", addr);
let root_dir = ArcPath(Arc::new(root_dir));
let create_service = make_service_fn(move |_| {
let root_dir = root_dir.clone();
async move {
Ok::<_, error::Error>(service_fn(move |req| {
let root_dir = root_dir.clone();
async move { handle(root_dir.as_ref(), req).await }
}))
}
});
let root_dir = ArcPath(Arc::new(root_dir));
let create_service = make_service_fn(move |_| {
let root_dir = root_dir.clone();
async move {
Ok::<_, error::Error>(service_fn(move |req| {
let root_dir = root_dir.clone();
async move { handle(root_dir.as_ref(), req).await }
}))
}
HyperServer::bind(&addr).serve(create_service).await
});
HyperServer::bind(&addr)
.serve(create_service)
.with_graceful_shutdown(async {
signal::ctrl_c()
.await
.expect("failed to install CTRL+C signal handler");
tracing::warn!(parent: &span, "CTRL+C signal caught and execution exited");
})
.await?;
handle_signals();
Ok(())
}
@@ -110,3 +105,20 @@ impl Default for Server {
Self::new()
}
}
#[cfg(not(windows))]
fn handle_signals() {
use crate::signals;
signals::wait(|sig: signals::Signal| {
let code = signals::as_int(sig);
tracing::warn!("Signal {} caught. Server execution exited.", code);
std::process::exit(code)
});
}
#[cfg(windows)]
fn handle_signals() {
}
@@ -0,0 +1,51 @@
use nix::errno::Errno;
use nix::libc::c_int;
use nix::sys::signal::{SIGCHLD, SIGINT, SIGTERM};
use nix::sys::wait::WaitStatus::{Exited, Signaled, StillAlive};
use nix::sys::wait::{waitpid, WaitPidFlag};
use nix::Error;
pub use signal::Signal;
pub fn wait<F>(func: F)
where
F: Fn(signal::Signal),
{
let sig_trap = signal::trap::Trap::trap(&[SIGTERM, SIGINT, SIGCHLD]);
for sig in sig_trap {
match sig {
SIGCHLD => {
loop {
match waitpid(None, Some(WaitPidFlag::WNOHANG)) {
Ok(Exited(pid, status)) => {
println!("{} exited with status {}", pid, status);
continue;
}
Ok(Signaled(pid, sig, _)) => {
println!("{} killed by {}", pid, sig as c_int);
continue;
}
Ok(StillAlive) => break,
Ok(status) => {
println!("Temporary status {:?}", status);
continue;
}
Err(Error::Sys(Errno::ECHILD)) => return,
Err(e) => {
panic!("Error {:?}", e);
}
}
}
}
sig => func(sig),
}
}
}
pub fn as_int(sig: signal::Signal) -> i32 {
sig as c_int
}