From 3a61db9e6f79f115248172bb2d574779711eabd5 Mon Sep 17 00:00:00 2001 From: ppom Date: Thu, 12 Feb 2026 12:00:00 +0100 Subject: [PATCH] plugin: shutdown: add function that permit graceful shutdown by signal Handling SIGTERM (etc) signals permit graceful shutdown, cleaning of resources etc. Added in ipset and cluster. --- plugins/reaction-plugin-cluster/src/main.rs | 2 ++ plugins/reaction-plugin-ipset/src/main.rs | 2 ++ plugins/reaction-plugin/Cargo.toml | 2 +- plugins/reaction-plugin/src/shutdown.rs | 24 +++++++++++++++++++++ 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/plugins/reaction-plugin-cluster/src/main.rs b/plugins/reaction-plugin-cluster/src/main.rs index b931026..d0269e5 100644 --- a/plugins/reaction-plugin-cluster/src/main.rs +++ b/plugins/reaction-plugin-cluster/src/main.rs @@ -237,6 +237,8 @@ impl PluginInfo for Plugin { } async fn start(&mut self) -> RemoteResult<()> { + self.cluster_shutdown.delegate().handle_quit_signals()?; + let mut db = { let path = PathBuf::from("."); let (cancellation_token, task_tracker_token) = self.cluster_shutdown.token().split(); diff --git a/plugins/reaction-plugin-ipset/src/main.rs b/plugins/reaction-plugin-ipset/src/main.rs index 268eb95..1117529 100644 --- a/plugins/reaction-plugin-ipset/src/main.rs +++ b/plugins/reaction-plugin-ipset/src/main.rs @@ -104,6 +104,8 @@ impl PluginInfo for Plugin { } async fn start(&mut self) -> RemoteResult<()> { + self.shutdown.delegate().handle_quit_signals()?; + let mut first_error = None; for (i, set) in self.sets.iter().enumerate() { // Retain if error diff --git a/plugins/reaction-plugin/Cargo.toml b/plugins/reaction-plugin/Cargo.toml index 1c22585..784555c 100644 --- a/plugins/reaction-plugin/Cargo.toml +++ b/plugins/reaction-plugin/Cargo.toml @@ -9,6 +9,6 @@ remoc.workspace = true serde.workspace = true serde_json.workspace = true tokio.workspace = true -tokio.features = ["io-std"] +tokio.features = ["io-std", "signal"] tokio-util.workspace = true tokio-util.features = ["rt"] diff --git a/plugins/reaction-plugin/src/shutdown.rs b/plugins/reaction-plugin/src/shutdown.rs index cc9ee4f..fb4bb40 100644 --- a/plugins/reaction-plugin/src/shutdown.rs +++ b/plugins/reaction-plugin/src/shutdown.rs @@ -36,7 +36,10 @@ //! } //! } //! ``` +//! +//! [`ShutdownDelegate::handle_quit_signals`] permits to handle SIGHUP, SIGINT and SIGTERM by gracefully shutting down tasks. +use tokio::signal::unix::{SignalKind, signal}; use tokio_util::{ sync::{CancellationToken, WaitForCancellationFuture}, task::task_tracker::{TaskTracker, TaskTrackerToken}, @@ -94,6 +97,27 @@ impl ShutdownDelegate { pub fn ask_shutdown(&self) { self.0.cancel(); } + + /// Ensure [`Self::ask_shutdown`] is called whenever we receive SIGHUP, + /// SIGTERM or SIGINT. Spawns a task that consumes self. + pub fn handle_quit_signals(self) -> Result<(), String> { + let err_str = |err| format!("could not register signal: {err}"); + + let mut sighup = signal(SignalKind::hangup()).map_err(err_str)?; + let mut sigint = signal(SignalKind::interrupt()).map_err(err_str)?; + let mut sigterm = signal(SignalKind::terminate()).map_err(err_str)?; + + tokio::spawn(async move { + let signal = tokio::select! { + _ = sighup.recv() => "SIGHUP", + _ = sigint.recv() => "SIGINT", + _ = sigterm.recv() => "SIGTERM", + }; + eprintln!("received {signal}, closing..."); + self.ask_shutdown(); + }); + Ok(()) + } } /// Created by a [`ShutdownController`].