Skip to main content

ares_agent/
emergency_stop.rs

1//! Remaining Cordis context types that live in the server crate:
2//! - [`EmergencyStop`] — native Service (kill switch)
3//!
4//! Tenant tool isolation uses `ares_agent::tenant_scope(ctx, tenant_id)` (`Tools` + `Execute`).
5//! `PostgresClient` and [`ares_agent::ContextProviderHandle`] are native Service
6//! types; handlers `ctx.get` them directly.
7
8use std::sync::Arc;
9use cordis::Context;
10use std::sync::atomic::AtomicBool;
11
12use cordis::Service;
13
14// Emergency stop
15/// Global agent-execution kill switch.
16pub struct EmergencyStop {
17    flag: AtomicBool,
18}
19
20impl EmergencyStop {
21    pub fn new(active: bool) -> Self {
22        Self {
23            flag: AtomicBool::new(active),
24        }
25    }
26
27    pub fn is_active(&self) -> bool {
28        self.flag.load(std::sync::atomic::Ordering::Relaxed)
29    }
30
31    pub fn set_active(&self, active: bool) {
32        self.flag
33            .store(active, std::sync::atomic::Ordering::Relaxed)
34    }
35}
36
37impl Service for EmergencyStop {
38    fn name(&self) -> &'static str {
39        "emergency_stop"
40    }
41    fn init(&self, _ctx: &Arc<Context>) -> cordis::ServiceInitFuture<'_> {
42        Box::pin(async { Ok(None) })
43    }
44    fn check(&self) -> bool {
45        true
46    }
47}
48
49// ContextProviderHandle (was ContextProviderService) lives in ares_agent::context_provider.
50
51#[cfg(test)]
52mod tests {
53    use super::*;
54    use cordis::Context;
55
56    #[test]
57    fn emergency_stop_readable_via_cordis() {
58        let ctx = Context::new_root();
59        ctx.provide(EmergencyStop::new(false));
60        let got = ctx.get::<EmergencyStop>().expect("provided");
61        assert!(!got.is_active());
62        got.set_active(true);
63        assert!(got.is_active());
64    }
65
66}