aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat
-rw-r--r--Cargo.lock10+10 −0
-rw-r--r--Cargo.toml3+3 −0
-rw-r--r--pkg/zorian.service6+4 −2
-rw-r--r--src/main.rs91+63 −28
4 files changed, 80 insertions, 30 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 55a7227..9499881 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3608,6 +3608,15 @@ dependencies = [
]
[[package]]
+name = "sd-notify"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b943eadf71d8b69e661330cb0e2656e31040acf21ee7708e2c238a0ec6af2bf4"
+dependencies = [
+ "libc",
+]
+
+[[package]]
name = "security-framework"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -5562,6 +5571,7 @@ dependencies = [
"hyper-util",
"minijinja",
"rustls",
+ "sd-notify",
"semver",
"serde",
"sqlx",
diff --git a/Cargo.toml b/Cargo.toml
index 9b4618f..762b60d 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -65,6 +65,9 @@ tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
url = "2.5"
uuid = { version = "1.19", features = ["v4", "v5"] }
+[target.'cfg(target_os = "linux")'.dependencies]
+sd-notify = { version = "0.4" }
+
[dev-dependencies]
cargo-deny = "0.19"
cargo-llvm-cov = "0.6"
diff --git a/pkg/zorian.service b/pkg/zorian.service
index ac99e25..64f34b5 100644
--- a/pkg/zorian.service
+++ b/pkg/zorian.service
@@ -8,11 +8,13 @@ After=time-sync.target network-online.target remote-fs.target nss-lookup.target
Wants=time-sync.target
[Service]
-Type=exec
+Type=notify
User=zorian
Group=zorian
Restart=always
RestartSec=30
+WatchdogSec=30
+NotifyAccess=main
ExecPaths=/usr/local/bin/zorian /usr/lib
ExecStart=/usr/local/bin/zorian --config=/etc/zorian.toml
LimitCORE=infinity
@@ -25,6 +27,7 @@ StateDirectory=%p
CacheDirectory=%p
RuntimeDirectory=%p
+UMask=0077
LockPersonality=yes
NoNewPrivileges=yes
PrivateDevices=yes
@@ -42,7 +45,6 @@ ProtectSystem=strict
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX
RestrictNamespaces=yes
RestrictSUIDSGID=yes
-UMask=0077
[Install]
# service should not start from the rescue shell (rescue.target).
diff --git a/src/main.rs b/src/main.rs
index fee8d4f..d6281ff 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -21,8 +21,10 @@ use axum::{
};
use axum_server::Handle;
use axum_server::tls_rustls::RustlsConfig;
+#[cfg(target_os = "linux")]
+use sd_notify::NotifyState;
use tokio::signal;
-use tracing::{error, info};
+use tracing::{error, info, trace};
use tracing_subscriber::{layer::SubscriberExt, registry::LookupSpan, util::SubscriberInitExt};
use crate::backends::zig::ZigController;
@@ -316,41 +318,74 @@ async fn main() {
);
}
- // Graceful shutdown
- let sigint = async {
- signal::ctrl_c()
- .await
- .expect("failed to install Ctrl+C handler");
+ let mut watchdog_ticker = tokio::time::interval(std::time::Duration::from_mins(1));
+
+ #[cfg(target_os = "linux")]
+ if sd_notify::booted().unwrap_or(false) {
+ sd_notify::notify(false, &[NotifyState::Ready]).ok();
+
+ let mut usec = 0u64;
+ (sd_notify::watchdog_enabled(true, &mut usec) && usec > 0).then(|| {
+ let interval = std::time::Duration::from_micros(usec) / 2;
+ info!(
+ interval_ms = interval.as_millis() as u64,
+ "watchdog enabled"
+ );
+ watchdog_ticker = tokio::time::interval(interval);
+ });
};
- let sigterm = {
- #[cfg(unix)]
- let terminate = async {
- signal::unix::signal(signal::unix::SignalKind::terminate())
- .expect("failed to install signal handler")
- .recv()
- .await;
- };
+ #[cfg(unix)]
+ let mut sigint = signal::unix::signal(signal::unix::SignalKind::interrupt())
+ .expect("failed to install signal handler");
+ #[cfg(windows)]
+ let mut sigint = signal::windows::signal(signal::windows::SignalKind::interrupt())
+ .expect("failed to install signal handler");
+
+ #[cfg(unix)]
+ let mut sigterm = signal::unix::signal(signal::unix::SignalKind::terminate())
+ .expect("failed to install signal handler");
+
+ loop {
+ let watchdog = watchdog_ticker.tick();
+
+ #[cfg(unix)]
+ let sigterm = sigterm.recv();
#[cfg(not(unix))]
- let terminate = std::future::pending::<()>();
+ let sigterm = std::future::pending::<()>();
- terminate
- };
- tokio::select! {
- _ = sigint => info!("received SIGINT, shutting down"),
- _ = sigterm => info!("received SIGTERM, shutting down"),
- result = tasks.join_next() => {
- match result {
- Some(Ok(())) => error!("listener exited unexpectedly, shutting down"),
- Some(Err(e)) => error!("listener failed: {e}, shutting down"),
- None => {
- error!("no listeners running");
- return;
+ tokio::select! {
+ _ = sigint.recv() => {
+ info!("received SIGINT, shutting down");
+ break;
+ },
+ _ = sigterm => {
+ info!("received SIGTERM, shutting down");
+ break;
+ },
+ _ = watchdog => {
+ trace!("server is alive");
+
+ #[cfg(target_os = "linux")]
+ sd_notify::notify(false, &[NotifyState::Watchdog]).ok();
+ },
+ result = tasks.join_next() => {
+ match result {
+ Some(Ok(())) => error!("listener exited unexpectedly, shutting down"),
+ Some(Err(e)) => error!("listener failed: {e}, shutting down"),
+ None => {
+ error!("no listeners running");
+ return;
+ }
}
- }
+ break;
+ },
}
}
+ #[cfg(target_os = "linux")]
+ sd_notify::notify(false, &[NotifyState::Stopping]).ok();
+
handle.graceful_shutdown(None);
// Wait for all listeners to finish with timeout