centralize: daemon syncs state with config, cleanup orphans
- rss daemon kills and cleans services not in config (rename-safe) - rss list also prunes orphaned state - rss start checks for already running before spawning - State: add supervise_dir/service_dir/list_pid_names helpers
This commit is contained in:
parent
74b9539149
commit
a7ce8405d1
2 changed files with 78 additions and 4 deletions
60
src/main.rs
60
src/main.rs
|
|
@ -74,6 +74,12 @@ fn cmd_start(name: &str, config: &Config, config_path: &str) {
|
|||
eprintln!("error: service '{}' not found in config", name);
|
||||
std::process::exit(1);
|
||||
}
|
||||
let state = State::new();
|
||||
let svc_pid = state.service_pid_path(name);
|
||||
if State::read_pid(&svc_pid).map_or(false, |p| process_running(p)) {
|
||||
eprintln!("error: '{}' is already running", name);
|
||||
std::process::exit(1);
|
||||
}
|
||||
let self_exe = std::env::current_exe().unwrap_or_else(|_| {
|
||||
eprintln!("error: cannot determine binary path");
|
||||
std::process::exit(1);
|
||||
|
|
@ -251,6 +257,7 @@ fn cmd_disable(name: &str, state: &State) {
|
|||
}
|
||||
|
||||
fn cmd_list(config: &Config, state: &State) {
|
||||
cleanup_orphans(config, state);
|
||||
let mut names: Vec<&String> = config.service.keys().collect();
|
||||
names.sort();
|
||||
|
||||
|
|
@ -292,7 +299,55 @@ fn cmd_list(config: &Config, state: &State) {
|
|||
}
|
||||
}
|
||||
|
||||
fn cleanup_orphans(config: &Config, state: &State) {
|
||||
for name in State::list_pid_names(&state.supervise_dir()) {
|
||||
if !config.service.contains_key(&name) {
|
||||
stop_orphan(&name, state);
|
||||
}
|
||||
}
|
||||
for name in State::list_pid_names(&state.service_dir()) {
|
||||
if !config.service.contains_key(&name) {
|
||||
State::remove_pid(&state.service_pid_path(&name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn stop_orphan(name: &str, state: &State) {
|
||||
let svc = state.service_pid_path(name);
|
||||
let sup = state.supervise_pid_path(name);
|
||||
|
||||
if let Some(pid) = State::read_pid(&svc) {
|
||||
if process_running(pid) {
|
||||
let _ = nix::sys::signal::kill(
|
||||
nix::unistd::Pid::from_raw(pid as i32),
|
||||
nix::sys::signal::Signal::SIGTERM,
|
||||
);
|
||||
wait_for_exit(pid, 5);
|
||||
if process_running(pid) {
|
||||
let _ = nix::sys::signal::kill(
|
||||
nix::unistd::Pid::from_raw(pid as i32),
|
||||
nix::sys::signal::Signal::SIGKILL,
|
||||
);
|
||||
wait_for_exit(pid, 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(pid) = State::read_pid(&sup) {
|
||||
if process_running(pid) {
|
||||
let _ = nix::sys::signal::kill(
|
||||
nix::unistd::Pid::from_raw(pid as i32),
|
||||
nix::sys::signal::Signal::SIGKILL,
|
||||
);
|
||||
wait_for_exit(pid, 3);
|
||||
}
|
||||
}
|
||||
State::remove_pid(&svc);
|
||||
State::remove_pid(&sup);
|
||||
}
|
||||
|
||||
fn cmd_daemon(config: &Config, state: &State, config_path: &str) {
|
||||
cleanup_orphans(config, state);
|
||||
|
||||
let enabled = state.list_enabled().unwrap_or_default();
|
||||
if enabled.is_empty() {
|
||||
println!("no enabled services");
|
||||
|
|
@ -300,15 +355,12 @@ fn cmd_daemon(config: &Config, state: &State, config_path: &str) {
|
|||
}
|
||||
|
||||
for name in &enabled {
|
||||
if !config.service.contains_key(name) {
|
||||
continue;
|
||||
}
|
||||
let svc_pid_path = state.service_pid_path(name);
|
||||
let already = State::read_pid(&svc_pid_path).map_or(false, |p| process_running(p));
|
||||
if already {
|
||||
continue;
|
||||
}
|
||||
println!("starting {}...", name);
|
||||
println!("{}", name);
|
||||
cmd_start(name, config, config_path);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
22
src/state.rs
22
src/state.rs
|
|
@ -26,10 +26,32 @@ impl State {
|
|||
self.state_dir.join("logs").join(format!("{}.log", name))
|
||||
}
|
||||
|
||||
pub fn supervise_dir(&self) -> PathBuf {
|
||||
self.state_dir.join("supervise")
|
||||
}
|
||||
|
||||
pub fn service_dir(&self) -> PathBuf {
|
||||
self.state_dir.join("service")
|
||||
}
|
||||
|
||||
pub fn enabled_path(&self, name: &str) -> PathBuf {
|
||||
self.config_dir.join("enabled").join(name)
|
||||
}
|
||||
|
||||
pub fn list_pid_names(dir: &PathBuf) -> Vec<String> {
|
||||
let mut names = Vec::new();
|
||||
if let Ok(entries) = std::fs::read_dir(dir) {
|
||||
for entry in entries.flatten() {
|
||||
let fname = entry.file_name();
|
||||
let fname = fname.to_string_lossy().to_string();
|
||||
if let Some(stripped) = fname.strip_suffix(".pid") {
|
||||
names.push(stripped.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
names
|
||||
}
|
||||
|
||||
pub fn write_pid(path: &PathBuf) -> std::io::Result<()> {
|
||||
Self::write_pid_with(path, std::process::id())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue