Skip to main content

agent_exec/
wait.rs

1//! Implementation of the `wait` sub-command.
2//!
3//! Polls `state.json` until the job leaves the `running` state or a timeout
4//! is reached.
5
6use anyhow::Result;
7use tracing::debug;
8
9use crate::jobstore::{JobDir, resolve_root};
10use crate::schema::{JobStatus, Response, WaitData};
11
12/// Options for the `wait` sub-command.
13#[derive(Debug)]
14pub struct WaitOpts<'a> {
15    pub job_id: &'a str,
16    pub root: Option<&'a str>,
17    /// Poll interval in milliseconds.
18    pub poll_ms: u64,
19    /// Total timeout in milliseconds; 0 = wait indefinitely.
20    pub timeout_ms: u64,
21}
22
23impl<'a> Default for WaitOpts<'a> {
24    fn default() -> Self {
25        WaitOpts {
26            job_id: "",
27            root: None,
28            poll_ms: 200,
29            timeout_ms: 0,
30        }
31    }
32}
33
34/// Execute `wait`: poll until done, then emit JSON.
35pub fn execute(opts: WaitOpts) -> Result<()> {
36    let root = resolve_root(opts.root);
37    let job_dir = JobDir::open(&root, opts.job_id)?;
38
39    let poll = std::time::Duration::from_millis(opts.poll_ms);
40    let deadline = if opts.timeout_ms > 0 {
41        Some(std::time::Instant::now() + std::time::Duration::from_millis(opts.timeout_ms))
42    } else {
43        None
44    };
45
46    loop {
47        let state = job_dir.read_state()?;
48        debug!(job_id = %opts.job_id, state = ?state.status(), "wait poll");
49
50        if *state.status() != JobStatus::Running {
51            let response = Response::new(
52                "wait",
53                WaitData {
54                    job_id: opts.job_id.to_string(),
55                    state: state.status().as_str().to_string(),
56                    exit_code: state.exit_code(),
57                },
58            );
59            response.print();
60            return Ok(());
61        }
62
63        if let Some(dl) = deadline
64            && std::time::Instant::now() >= dl
65        {
66            // Timed out — still running.
67            let response = Response::new(
68                "wait",
69                WaitData {
70                    job_id: opts.job_id.to_string(),
71                    state: JobStatus::Running.as_str().to_string(),
72                    exit_code: None,
73                },
74            );
75            response.print();
76            return Ok(());
77        }
78
79        std::thread::sleep(poll);
80    }
81}