From 18195390a942313abd2ba69c0f699225872e3f06 Mon Sep 17 00:00:00 2001 From: Tyler Anton Date: Wed, 14 Aug 2024 16:40:13 -0700 Subject: [PATCH] Refactor Signal Handling to be Cross-Platform (#71) * cross-platform signals * cleanup tokio import --- Cargo.lock | 11 --------- Cargo.toml | 1 - src/server/mod.rs | 58 +++++++++++++++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8a8c327..8156362 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1806,7 +1806,6 @@ dependencies = [ "serde", "serde_json", "serialport", - "signal-hook", "slog", "slog-async", "slog-json", @@ -3068,16 +3067,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.2" diff --git a/Cargo.toml b/Cargo.toml index f7b1fad..ee54d0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,6 @@ schemars = { version = "0.8", features = ["chrono", "uuid1", "bigdecimal"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" serialport = "4.5.0" -signal-hook = "0.3" slog = "2.7.0" slog-async = "2.7.0" slog-json = "2.6.1" diff --git a/src/server/mod.rs b/src/server/mod.rs index a2df9cf..4e73495 100644 --- a/src/server/mod.rs +++ b/src/server/mod.rs @@ -5,13 +5,48 @@ use std::{env, net::SocketAddr, sync::Arc}; use anyhow::{anyhow, Result}; use dropshot::{ApiDescription, ConfigDropshot, HttpServerStarter}; -use signal_hook::{ - consts::{SIGINT, SIGTERM}, - iterator::Signals, -}; use crate::{config::Config, network_printer::NetworkPrinterManufacturer, server::context::Context}; +async fn handle_signals(api_context: Arc) -> Result<()> { + #[cfg(unix)] + { + use tokio::signal::unix::{signal, SignalKind}; + + let mut sigint = signal(SignalKind::interrupt()).map_err(|e| { + slog::error!(api_context.logger, "Failed to set up SIGINT handler: {:?}", e); + e + })?; + let mut sigterm = signal(SignalKind::terminate()).map_err(|e| { + slog::error!(api_context.logger, "Failed to set up SIGTERM handler: {:?}", e); + e + })?; + + tokio::select! { + _ = sigint.recv() => { + slog::info!(api_context.logger, "received SIGINT"); + } + _ = sigterm.recv() => { + slog::info!(api_context.logger, "received SIGTERM"); + } + } + } + + #[cfg(windows)] + { + tokio::signal::ctrl_c().await.map_err(|e| { + slog::error!(api_context.logger, "Failed to set up Ctrl+C handler: {:?}", e); + anyhow::Error::new(e) + })?; + + slog::info!(api_context.logger, "received Ctrl+C (SIGINT)"); + } + + slog::info!(api_context.logger, "triggering cleanup..."); + slog::info!(api_context.logger, "all clean, exiting!"); + std::process::exit(0); +} + /// Create an API description for the server. pub fn create_api_description() -> Result>> { fn register_endpoints(api: &mut ApiDescription>) -> Result<(), String> { @@ -90,20 +125,9 @@ pub async fn server(s: &crate::Server, opts: &crate::Opts, config: &Config) -> R // For Cloud run & ctrl+c, shutdown gracefully. // "The main process inside the container will receive SIGTERM, and after a grace period, // SIGKILL." - // Regsitering SIGKILL here will panic at runtime, so let's avoid that. - let mut signals = Signals::new([SIGINT, SIGTERM])?; - + // Registering SIGKILL here will panic at runtime, so let's avoid that. let cloned_api_context = api_context.clone(); - tokio::spawn(async move { - if let Some(sig) = signals.forever().next() { - slog::info!(cloned_api_context.logger, "received signal: {:?}", sig); - slog::info!(cloned_api_context.logger, "triggering cleanup..."); - - // Exit the process. - slog::info!(cloned_api_context.logger, "all clean, exiting!"); - std::process::exit(0); - } - }); + tokio::spawn(handle_signals(cloned_api_context)); // Start all the discovery tasks. tokio::spawn(async move {