use crate::cli::daemon::DaemonServeArgs;
use crate::config::Resolved;
use anyhow::{Context, Result};
use super::{
DAEMON_LOCK_DIR, DaemonState, clear_daemon_runtime_artifacts, write_daemon_ready,
write_daemon_state,
};
#[cfg(unix)]
use crate::signal;
pub fn serve(resolved: &Resolved, args: DaemonServeArgs) -> Result<()> {
let cache_dir = resolved.repo_root.join(".ralph/cache");
let daemon_lock_dir = cache_dir.join(DAEMON_LOCK_DIR);
let _lock = crate::lock::acquire_dir_lock(&daemon_lock_dir, "daemon", false)
.context("Failed to acquire daemon lock")?;
let state = DaemonState {
version: 1,
pid: std::process::id(),
started_at: crate::timeutil::now_utc_rfc3339()?,
repo_root: resolved.repo_root.display().to_string(),
command: std::env::args().collect::<Vec<_>>().join(" "),
};
write_daemon_state(&cache_dir, &state)?;
write_daemon_ready(&cache_dir, state.pid)?;
log::info!(
"Daemon started (PID: {}, empty_poll={}ms, wait_poll={}ms)",
state.pid,
args.empty_poll_ms,
args.wait_poll_ms
);
#[cfg(unix)]
{
use signal_hook::consts::SIGTERM;
use signal_hook::iterator::Signals;
use std::thread;
let cache_dir_for_handler = cache_dir.clone();
let mut signals = Signals::new([SIGTERM]).context("Failed to register SIGTERM handler")?;
thread::Builder::new()
.name("sigterm-handler".to_string())
.spawn(move || {
for sig in signals.forever() {
if sig == SIGTERM {
log::info!("SIGTERM received; requesting graceful shutdown");
if let Err(e) = signal::create_stop_signal(&cache_dir_for_handler) {
log::warn!("Failed to create stop signal on SIGTERM: {}", e);
}
break;
}
}
})
.context("Failed to spawn SIGTERM handler thread")?;
}
let result = crate::commands::run::run_loop(
resolved,
crate::commands::run::RunLoopOptions {
max_tasks: 0, agent_overrides: crate::agent::AgentOverrides::default(),
force: true, auto_resume: false,
starting_completed: 0,
non_interactive: true,
parallel_workers: None,
wait_when_blocked: true,
wait_poll_ms: args.wait_poll_ms,
wait_timeout_seconds: 0, notify_when_unblocked: args.notify_when_unblocked,
wait_when_empty: true,
empty_poll_ms: args.empty_poll_ms,
run_event_handler: None,
},
);
log::info!("Daemon shutting down");
clear_daemon_runtime_artifacts(&cache_dir, false);
result
}