support reloading config via SIGUSR1

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2025-01-28 20:55:28 +00:00
parent a567e314e9
commit 2f449ba47d
7 changed files with 75 additions and 10 deletions

View file

@ -1524,6 +1524,11 @@
#
#listening = true
# Enables configuration reload when the server receives SIGUSR1 on
# supporting platforms.
#
#config_reload_signal = true
[global.tls]
# Path to a valid TLS certificate file.

View file

@ -1,6 +1,6 @@
use std::{fmt::Write, path::PathBuf, sync::Arc};
use conduwuit::{info, utils::time, warn, Config, Err, Result};
use conduwuit::{info, utils::time, warn, Err, Result};
use ruma::events::room::message::RoomMessageEventContent;
use crate::admin_command;
@ -32,15 +32,8 @@ pub(super) async fn reload_config(
&self,
path: Option<PathBuf>,
) -> Result<RoomMessageEventContent> {
use conduwuit::config::check;
let path = path.as_deref().into_iter();
let new = Config::load(path).and_then(|raw| Config::new(&raw))?;
let old = &self.services.server.config;
check::reload(old, &new)?;
self.services.server.config.update(new)?;
self.services.config.reload(path)?;
Ok(RoomMessageEventContent::text_plain("Successfully reconfigured."))
}

View file

@ -1742,6 +1742,13 @@ pub struct Config {
#[serde(default = "true_fn")]
pub listening: bool,
/// Enables configuration reload when the server receives SIGUSR1 on
/// supporting platforms.
///
/// default: true
#[serde(default = "true_fn")]
pub config_reload_signal: bool,
#[serde(flatten)]
#[allow(clippy::zero_sized_map_values)]
// this is a catchall, the map shouldn't be zero at runtime

View file

@ -16,6 +16,7 @@ pub(super) async fn signal(server: Arc<Server>) {
let mut quit = unix::signal(SignalKind::quit()).expect("SIGQUIT handler");
let mut term = unix::signal(SignalKind::terminate()).expect("SIGTERM handler");
let mut usr1 = unix::signal(SignalKind::user_defined1()).expect("SIGUSR1 handler");
loop {
trace!("Installed signal handlers");
let sig: &'static str;
@ -23,6 +24,7 @@ pub(super) async fn signal(server: Arc<Server>) {
_ = signal::ctrl_c() => { sig = "SIGINT"; },
_ = quit.recv() => { sig = "SIGQUIT"; },
_ = term.recv() => { sig = "SIGTERM"; },
_ = usr1.recv() => { sig = "SIGUSR1"; },
}
warn!("Received {sig}");

55
src/service/config/mod.rs Normal file
View file

@ -0,0 +1,55 @@
use std::{iter, path::Path, sync::Arc};
use async_trait::async_trait;
use conduwuit::{
config::{check, Config},
error, implement, Result, Server,
};
pub struct Service {
server: Arc<Server>,
}
const SIGNAL: &str = "SIGUSR1";
#[async_trait]
impl crate::Service for Service {
fn build(args: crate::Args<'_>) -> Result<Arc<Self>> {
Ok(Arc::new(Self { server: args.server.clone() }))
}
async fn worker(self: Arc<Self>) -> Result {
while self.server.running() {
if self.server.signal.subscribe().recv().await == Ok(SIGNAL) {
if let Err(e) = self.handle_reload() {
error!("Failed to reload config: {e}");
}
}
}
Ok(())
}
fn name(&self) -> &str { crate::service::make_name(std::module_path!()) }
}
#[implement(Service)]
fn handle_reload(&self) -> Result {
if self.server.config.config_reload_signal {
self.reload(iter::empty())?;
}
Ok(())
}
#[implement(Service)]
pub fn reload<'a, I>(&self, paths: I) -> Result<Arc<Config>>
where
I: Iterator<Item = &'a Path>,
{
let old = self.server.config.clone();
let new = Config::load(paths).and_then(|raw| Config::new(&raw))?;
check::reload(&old, &new)?;
self.server.config.update(new)
}

View file

@ -9,6 +9,7 @@ pub mod account_data;
pub mod admin;
pub mod appservice;
pub mod client;
pub mod config;
pub mod emergency;
pub mod federation;
pub mod globals;

View file

@ -10,7 +10,7 @@ use database::Database;
use tokio::sync::Mutex;
use crate::{
account_data, admin, appservice, client, emergency, federation, globals, key_backups,
account_data, admin, appservice, client, config, emergency, federation, globals, key_backups,
manager::Manager,
media, presence, pusher, resolver, rooms, sending, server_keys, service,
service::{Args, Map, Service},
@ -21,6 +21,7 @@ pub struct Services {
pub account_data: Arc<account_data::Service>,
pub admin: Arc<admin::Service>,
pub appservice: Arc<appservice::Service>,
pub config: Arc<config::Service>,
pub client: Arc<client::Service>,
pub emergency: Arc<emergency::Service>,
pub globals: Arc<globals::Service>,
@ -68,6 +69,7 @@ impl Services {
appservice: build!(appservice::Service),
resolver: build!(resolver::Service),
client: build!(client::Service),
config: build!(config::Service),
emergency: build!(emergency::Service),
globals: build!(globals::Service),
key_backups: build!(key_backups::Service),