Skip to main content

sqlite_graphrag/commands/
daemon.rs

1use 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    /// Idle timeout in seconds before the daemon auto-shuts down to release the embedding model.
18    /// Default 600s; raise for long-running batch ingestion to avoid cold-start overhead.
19    #[arg(long, default_value_t = DAEMON_IDLE_SHUTDOWN_SECS)]
20    pub idle_shutdown_secs: u64,
21    /// Send a health-check ping to a running daemon and exit. Returns NotFound (exit 4) if no daemon.
22    #[arg(long)]
23    pub ping: bool,
24    /// Request graceful shutdown of a running daemon. Returns NotFound (exit 4) if no daemon.
25    #[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}