sqlite_graphrag/commands/
daemon.rs1use crate::constants::DAEMON_IDLE_SHUTDOWN_SECS;
2use crate::errors::AppError;
3use crate::output;
4use crate::paths::AppPaths;
5
6#[derive(clap::Args)]
7#[command(after_long_help = "EXAMPLES:\n \
8 # Start the embedding daemon in the foreground (default 600s idle timeout)\n \
9 sqlite-graphrag daemon\n\n \
10 # Start with a longer idle timeout for batch ingestion\n \
11 sqlite-graphrag daemon --idle-shutdown-secs 3600\n\n \
12 # Health-check a running daemon (exit 4 if not running)\n \
13 sqlite-graphrag daemon --ping\n\n \
14 # Request graceful shutdown of a running daemon\n \
15 sqlite-graphrag daemon --stop")]
16pub struct DaemonArgs {
17 #[arg(long, default_value_t = DAEMON_IDLE_SHUTDOWN_SECS)]
20 pub idle_shutdown_secs: u64,
21 #[arg(long)]
23 pub ping: bool,
24 #[arg(long)]
26 pub stop: bool,
27 #[arg(long, hide = true, help = "No-op; JSON is always emitted on stdout")]
28 pub json: bool,
29 #[arg(long, env = "SQLITE_GRAPHRAG_DB_PATH")]
30 pub db: Option<String>,
31}
32
33pub fn run(args: DaemonArgs) -> Result<(), AppError> {
34 let _ = args.json;
35 let paths = AppPaths::resolve(args.db.as_deref())?;
36 paths.ensure_dirs()?;
37
38 if args.ping {
39 let response = crate::daemon::try_ping(&paths.models)?
40 .ok_or_else(|| AppError::NotFound("daemon not running".to_string()))?;
41 output::emit_json(&response)?;
42 return Ok(());
43 }
44
45 if args.stop {
46 let response = crate::daemon::try_shutdown(&paths.models)?
47 .ok_or_else(|| AppError::NotFound("daemon not running".to_string()))?;
48 output::emit_json(&response)?;
49 return Ok(());
50 }
51
52 crate::daemon::run(&paths.models, args.idle_shutdown_secs)
53}