Skip to main content

meerkat_core/lifecycle/
run_control.rs

1//! ยง20 Out-of-band run control commands.
2//!
3//! These are delivered to core on a SEPARATE channel from `RunPrimitive`.
4//! They interrupt or stop the current run without going through the input queue.
5
6use serde::{Deserialize, Serialize};
7
8/// Out-of-band control commands for the core executor.
9#[non_exhaustive]
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(tag = "command", rename_all = "snake_case")]
12pub enum RunControlCommand {
13    /// Cancel the currently executing run.
14    /// The run should terminate gracefully (cleanup, emit RunCancelled).
15    CancelCurrentRun {
16        /// Why the run is being cancelled.
17        #[serde(default)]
18        reason: String,
19    },
20    /// Stop the runtime executor entirely.
21    /// No further runs will be started.
22    StopRuntimeExecutor {
23        /// Why the executor is being stopped.
24        #[serde(default)]
25        reason: String,
26    },
27}
28
29#[cfg(test)]
30#[allow(clippy::unwrap_used)]
31mod tests {
32    use super::*;
33
34    #[test]
35    fn cancel_serde_roundtrip() {
36        let cmd = RunControlCommand::CancelCurrentRun {
37            reason: "user request".into(),
38        };
39        let json = serde_json::to_value(&cmd).unwrap();
40        assert_eq!(json["command"], "cancel_current_run");
41        let parsed: RunControlCommand = serde_json::from_value(json).unwrap();
42        assert_eq!(cmd, parsed);
43    }
44
45    #[test]
46    fn stop_serde_roundtrip() {
47        let cmd = RunControlCommand::StopRuntimeExecutor {
48            reason: "shutdown".into(),
49        };
50        let json = serde_json::to_value(&cmd).unwrap();
51        assert_eq!(json["command"], "stop_runtime_executor");
52        let parsed: RunControlCommand = serde_json::from_value(json).unwrap();
53        assert_eq!(cmd, parsed);
54    }
55}