mirror of
https://gitlab.com/veloren/veloren.git
synced 2024-08-30 18:12:32 +00:00
allow using other signals for graceful shutdown
This commit is contained in:
parent
f159dd5357
commit
ae66f5db43
@ -55,10 +55,7 @@ fn main() -> io::Result<()> {
|
|||||||
// noninteractive implies basic
|
// noninteractive implies basic
|
||||||
let basic = basic || noninteractive;
|
let basic = basic || noninteractive;
|
||||||
|
|
||||||
let sigusr1_signal = Arc::new(AtomicBool::new(false));
|
let shutdown_signal = Arc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
|
||||||
let _ = signal_hook::flag::register(signal_hook::consts::SIGUSR1, Arc::clone(&sigusr1_signal));
|
|
||||||
|
|
||||||
let (_guards, _guards2) = if basic {
|
let (_guards, _guards2) = if basic {
|
||||||
(Vec::new(), common_frontend::init_stdout(None))
|
(Vec::new(), common_frontend::init_stdout(None))
|
||||||
@ -69,6 +66,16 @@ fn main() -> io::Result<()> {
|
|||||||
// Load settings
|
// Load settings
|
||||||
let settings = settings::Settings::load();
|
let settings = settings::Settings::load();
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
{
|
||||||
|
for signal in &settings.shutdown_signals {
|
||||||
|
let _ = signal_hook::flag::register(
|
||||||
|
*signal as core::ffi::c_int,
|
||||||
|
Arc::clone(&shutdown_signal),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Determine folder to save server data in
|
// Determine folder to save server data in
|
||||||
let server_data_dir = {
|
let server_data_dir = {
|
||||||
let mut path = common_base::userdata_dir_workspace!();
|
let mut path = common_base::userdata_dir_workspace!();
|
||||||
@ -234,7 +241,7 @@ fn main() -> io::Result<()> {
|
|||||||
"Server is ready to accept connections."
|
"Server is ready to accept connections."
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut shutdown_coordinator = ShutdownCoordinator::new(Arc::clone(&sigusr1_signal));
|
let mut shutdown_coordinator = ShutdownCoordinator::new(Arc::clone(&shutdown_signal));
|
||||||
|
|
||||||
// Set up an fps clock
|
// Set up an fps clock
|
||||||
let mut clock = Clock::new(Duration::from_secs_f64(1.0 / TPS as f64));
|
let mut clock = Clock::new(Duration::from_secs_f64(1.0 / TPS as f64));
|
||||||
|
@ -6,6 +6,15 @@ use std::{
|
|||||||
};
|
};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
|
#[repr(i32)]
|
||||||
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
|
pub enum ShutdownSignal {
|
||||||
|
SIGUSR1 = signal_hook::consts::SIGUSR1,
|
||||||
|
SIGUSR2 = signal_hook::consts::SIGUSR2,
|
||||||
|
SIGTERM = signal_hook::consts::SIGTERM,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub struct Settings {
|
pub struct Settings {
|
||||||
@ -15,6 +24,7 @@ pub struct Settings {
|
|||||||
/// SECRET API HEADER used to access the chat api, if disabled the API is
|
/// SECRET API HEADER used to access the chat api, if disabled the API is
|
||||||
/// unreachable
|
/// unreachable
|
||||||
pub web_chat_secret: Option<String>,
|
pub web_chat_secret: Option<String>,
|
||||||
|
pub shutdown_signals: Vec<ShutdownSignal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Settings {
|
impl Default for Settings {
|
||||||
@ -24,6 +34,7 @@ impl Default for Settings {
|
|||||||
update_shutdown_message: "The server is restarting for an update".to_owned(),
|
update_shutdown_message: "The server is restarting for an update".to_owned(),
|
||||||
web_address: SocketAddr::from((Ipv4Addr::LOCALHOST, 14005)),
|
web_address: SocketAddr::from((Ipv4Addr::LOCALHOST, 14005)),
|
||||||
web_chat_secret: None,
|
web_chat_secret: None,
|
||||||
|
shutdown_signals: vec![ShutdownSignal::SIGUSR1],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ use std::{
|
|||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
|
|
||||||
/// Coordinates the shutdown procedure for the server, which can be initiated by
|
/// Coordinates the shutdown procedure for the server, which can be initiated by
|
||||||
/// either the TUI console interface or by sending the server the SIGUSR1 signal
|
/// either the TUI console interface or by sending the server the SIGUSR1 (or
|
||||||
/// which indicates the server is restarting due to an update.
|
/// others) signal which indicates the server is restarting due to an update.
|
||||||
pub(crate) struct ShutdownCoordinator {
|
pub(crate) struct ShutdownCoordinator {
|
||||||
/// The instant that the last shutdown message was sent, used for
|
/// The instant that the last shutdown message was sent, used for
|
||||||
/// calculating when to send the next shutdown message
|
/// calculating when to send the next shutdown message
|
||||||
@ -28,19 +28,19 @@ pub(crate) struct ShutdownCoordinator {
|
|||||||
/// The message to use for the shutdown warning message that is sent to all
|
/// The message to use for the shutdown warning message that is sent to all
|
||||||
/// connected players
|
/// connected players
|
||||||
shutdown_message: String,
|
shutdown_message: String,
|
||||||
/// Provided by `signal_hook` to allow observation of the SIGUSR1 signal
|
/// Provided by `signal_hook` to allow observation of a shutdown signal
|
||||||
sigusr1_signal: Arc<AtomicBool>,
|
shutdown_signal: Arc<AtomicBool>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ShutdownCoordinator {
|
impl ShutdownCoordinator {
|
||||||
pub fn new(sigusr1_signal: Arc<AtomicBool>) -> Self {
|
pub fn new(shutdown_signal: Arc<AtomicBool>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
last_shutdown_msg: Instant::now(),
|
last_shutdown_msg: Instant::now(),
|
||||||
msg_interval: Duration::from_secs(30),
|
msg_interval: Duration::from_secs(30),
|
||||||
shutdown_initiated_at: None,
|
shutdown_initiated_at: None,
|
||||||
shutdown_grace_period: Duration::from_secs(0),
|
shutdown_grace_period: Duration::from_secs(0),
|
||||||
shutdown_message: String::new(),
|
shutdown_message: String::new(),
|
||||||
sigusr1_signal,
|
shutdown_signal,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,8 +81,8 @@ impl ShutdownCoordinator {
|
|||||||
/// returns `true` which triggers the loop in `main.rs` to break and
|
/// returns `true` which triggers the loop in `main.rs` to break and
|
||||||
/// exit the server process.
|
/// exit the server process.
|
||||||
pub fn check(&mut self, server: &mut Server, settings: &Settings) -> bool {
|
pub fn check(&mut self, server: &mut Server, settings: &Settings) -> bool {
|
||||||
// Check whether SIGUSR1 has been set
|
// Check whether shutdown has been set
|
||||||
self.check_sigusr1_signal(server, settings);
|
self.check_shutdown_signal(server, settings);
|
||||||
|
|
||||||
// If a shutdown is in progress, check whether it's time to send another warning
|
// If a shutdown is in progress, check whether it's time to send another warning
|
||||||
// message or shut down if the grace period has expired.
|
// message or shut down if the grace period has expired.
|
||||||
@ -109,14 +109,14 @@ impl ShutdownCoordinator {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks whether the SIGUSR1 signal has been set, which is used to trigger
|
/// Checks whether a shutdown (SIGUSR1 by default) signal has been set,
|
||||||
/// a graceful shutdown for an update. [Watchtower](https://containrrr.dev/watchtower/) is configured on the main
|
/// which is used to trigger a graceful shutdown for an update. [Watchtower](https://containrrr.dev/watchtower/) is configured on the main
|
||||||
/// Veloren server to send SIGUSR1 instead of SIGTERM which allows us to
|
/// Veloren server to send SIGUSR1 instead of SIGTERM which allows us to
|
||||||
/// react specifically to shutdowns that are for an update.
|
/// react specifically to shutdowns that are for an update.
|
||||||
/// NOTE: SIGUSR1 is not supported on Windows
|
/// NOTE: SIGUSR1 is not supported on Windows
|
||||||
fn check_sigusr1_signal(&mut self, server: &mut Server, settings: &Settings) {
|
fn check_shutdown_signal(&mut self, server: &mut Server, settings: &Settings) {
|
||||||
if self.sigusr1_signal.load(Ordering::Relaxed) && self.shutdown_initiated_at.is_none() {
|
if self.shutdown_signal.load(Ordering::Relaxed) && self.shutdown_initiated_at.is_none() {
|
||||||
info!("Received SIGUSR1 signal, initiating graceful shutdown");
|
info!("Received shutdown signal, initiating graceful shutdown");
|
||||||
let grace_period =
|
let grace_period =
|
||||||
Duration::from_secs(u64::from(settings.update_shutdown_grace_period_secs));
|
Duration::from_secs(u64::from(settings.update_shutdown_grace_period_secs));
|
||||||
let shutdown_message = settings.update_shutdown_message.to_owned();
|
let shutdown_message = settings.update_shutdown_message.to_owned();
|
||||||
@ -124,7 +124,7 @@ impl ShutdownCoordinator {
|
|||||||
|
|
||||||
// Reset the SIGUSR1 signal indicator in case shutdown is aborted and we need to
|
// Reset the SIGUSR1 signal indicator in case shutdown is aborted and we need to
|
||||||
// trigger shutdown again
|
// trigger shutdown again
|
||||||
self.sigusr1_signal.store(false, Ordering::Relaxed);
|
self.shutdown_signal.store(false, Ordering::Relaxed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user