Skip to main content

harn_cli/commands/orchestrator/harness/
config.rs

1//! Public configuration and error types for the in-process orchestrator harness.
2
3use std::net::SocketAddr;
4use std::path::PathBuf;
5use std::sync::Arc;
6use std::time::Duration;
7
8use harn_vm::clock::{Clock, RealClock};
9
10use super::super::errors::OrchestratorError;
11use super::super::role::OrchestratorRole;
12use super::super::tls::TlsFiles;
13
14// ── Public config ─────────────────────────────────────────────────────────────
15
16/// Drain limits applied during graceful shutdown.
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub struct DrainConfig {
19    pub max_items: usize,
20    pub deadline: Duration,
21}
22
23impl Default for DrainConfig {
24    fn default() -> Self {
25        Self {
26            max_items: crate::package::default_orchestrator_drain_max_items(),
27            deadline: Duration::from_secs(
28                crate::package::default_orchestrator_drain_deadline_seconds(),
29            ),
30        }
31    }
32}
33
34/// Topic-pump concurrency limit.
35#[derive(Clone, Copy, Debug, PartialEq, Eq)]
36pub struct PumpConfig {
37    pub max_outstanding: usize,
38}
39
40impl Default for PumpConfig {
41    fn default() -> Self {
42        Self {
43            max_outstanding: crate::package::default_orchestrator_pump_max_outstanding(),
44        }
45    }
46}
47
48/// Configuration for `OrchestratorHarness::start`.
49#[derive(Clone, Debug)]
50pub struct OrchestratorConfig {
51    pub manifest_path: PathBuf,
52    pub state_dir: PathBuf,
53    pub bind: SocketAddr,
54    pub role: OrchestratorRole,
55    pub watch_manifest: bool,
56    pub mcp: bool,
57    pub mcp_path: String,
58    pub mcp_sse_path: String,
59    pub mcp_messages_path: String,
60    pub tls: Option<TlsFiles>,
61    pub shutdown_timeout: Duration,
62    pub drain: DrainConfig,
63    pub pump: PumpConfig,
64    /// When `Some`, installs an observability tracing subscriber.  Tests
65    /// should leave this `None` to avoid conflicts with the test runtime.
66    pub log_format: Option<harn_vm::observability::otel::LogFormat>,
67    /// Time + sleep substrate. Defaults to [`RealClock`]; tests inject
68    /// [`harn_vm::clock::PausedClock`] via [`OrchestratorConfig::with_clock`].
69    pub clock: Arc<dyn Clock>,
70    /// When `true`, the Prometheus `/metrics` endpoint is exposed
71    /// without auth (mirrors the `--public-metrics` CLI flag and the
72    /// `HARN_ORCHESTRATOR_PUBLIC_METRICS` env var). Defaults to
73    /// `false` so a public bind does not leak route catalog and
74    /// throughput counters.
75    pub public_metrics: bool,
76}
77
78impl OrchestratorConfig {
79    /// Minimal defaults suitable for integration tests.
80    pub fn for_test(manifest_path: PathBuf, state_dir: PathBuf) -> Self {
81        Self {
82            manifest_path,
83            state_dir,
84            bind: "127.0.0.1:0".parse().unwrap(),
85            role: OrchestratorRole::SingleTenant,
86            watch_manifest: false,
87            mcp: false,
88            mcp_path: "/mcp".to_string(),
89            mcp_sse_path: "/sse".to_string(),
90            mcp_messages_path: "/messages".to_string(),
91            tls: None,
92            shutdown_timeout: Duration::from_secs(5),
93            drain: DrainConfig::default(),
94            pump: PumpConfig::default(),
95            log_format: None,
96            clock: RealClock::arc(),
97            public_metrics: false,
98        }
99    }
100
101    /// Inject a custom [`Clock`]. Production callers leave the default
102    /// [`RealClock`]; harness-driven tests pass a
103    /// [`harn_vm::clock::PausedClock`] so cron and the dispatcher run on
104    /// virtual time.
105    pub fn with_clock(mut self, clock: Arc<dyn Clock>) -> Self {
106        self.clock = clock;
107        self
108    }
109}
110
111// ── Public harness types ──────────────────────────────────────────────────────
112
113/// Summary returned by `OrchestratorHarness::shutdown`.
114#[derive(Debug)]
115pub struct ShutdownReport {
116    #[allow(dead_code)]
117    pub timed_out: bool,
118}
119
120/// Error type for harness operations.
121#[derive(Debug)]
122pub struct HarnessError(pub String);
123
124impl std::fmt::Display for HarnessError {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        f.write_str(&self.0)
127    }
128}
129
130impl From<OrchestratorError> for HarnessError {
131    fn from(error: OrchestratorError) -> Self {
132        HarnessError(error.to_string())
133    }
134}
135
136impl From<String> for HarnessError {
137    fn from(s: String) -> Self {
138        HarnessError(s)
139    }
140}