Skip to main content

camel_component_api/
component_context.rs

1use std::sync::Arc;
2
3use camel_api::{AsyncHealthCheck, MetricsCollector, PlatformService};
4use camel_language_api::Language;
5
6use crate::Component;
7
8/// Runtime context passed to components during endpoint creation.
9pub trait ComponentContext: Send + Sync {
10    /// Resolve a component by scheme.
11    fn resolve_component(&self, scheme: &str) -> Option<Arc<dyn Component>>;
12
13    /// Resolve a language by name.
14    fn resolve_language(&self, name: &str) -> Option<Arc<dyn Language>>;
15
16    /// Access the active metrics collector.
17    fn metrics(&self) -> Arc<dyn MetricsCollector>;
18
19    /// Context-global counter of accepted-not-completed exchanges
20    /// (drainclaim). Production contexts return the counter installed on
21    /// every `ConsumerContext` at consumer start and read by
22    /// `CamelContext::total_in_flight()` for the drain verdict. Default
23    /// `None` keeps test contexts uncounted.
24    fn in_flight_counter(&self) -> Option<std::sync::Arc<std::sync::atomic::AtomicU64>> {
25        None
26    }
27
28    /// Snapshot of the `[observability.metrics].components` lever —
29    /// gates only the uniform component-operations family served through
30    /// `RuntimeObservability::component_metrics()`; error-family
31    /// emission is never lever-gated. Default false (opt-in);
32    /// `CamelContext` overrides this with its `MetricsLeversConfig`
33    /// snapshot.
34    fn component_metrics_enabled(&self) -> bool {
35        false
36    }
37
38    /// Access the active health-check registry.
39    ///
40    /// Used by component code paths that need to pin a route Unhealthy
41    /// (category (g) per ADR-0012). Default: NoOp — tests/examples inherit
42    /// the no-op. Concrete runtimes (CamelContext) override to return the
43    /// real registry.
44    fn health(&self) -> Arc<dyn crate::HealthCheckRegistry> {
45        Arc::new(crate::NoOpHealthCheckRegistry)
46    }
47
48    /// Access the active platform service.
49    fn platform_service(&self) -> Arc<dyn PlatformService>;
50
51    fn register_route_health_check(&self, route_id: &str, check: Arc<dyn AsyncHealthCheck>);
52
53    fn unregister_route_health_check(&self, route_id: &str);
54
55    fn route_id(&self) -> Option<&str> {
56        None
57    }
58
59    fn register_current_route_health_check(&self, check: Arc<dyn AsyncHealthCheck>) {
60        if let Some(id) = self.route_id() {
61            self.register_route_health_check(id, check);
62        }
63    }
64}
65
66/// Default no-op component context for tests/examples.
67pub struct NoOpComponentContext;
68
69impl ComponentContext for NoOpComponentContext {
70    fn resolve_component(&self, _scheme: &str) -> Option<Arc<dyn Component>> {
71        None
72    }
73
74    fn resolve_language(&self, _name: &str) -> Option<Arc<dyn Language>> {
75        None
76    }
77
78    fn metrics(&self) -> Arc<dyn MetricsCollector> {
79        Arc::new(camel_api::NoOpMetrics)
80    }
81
82    fn platform_service(&self) -> Arc<dyn PlatformService> {
83        Arc::new(camel_api::NoopPlatformService::default())
84    }
85
86    fn register_route_health_check(&self, _route_id: &str, _check: Arc<dyn AsyncHealthCheck>) {}
87
88    fn unregister_route_health_check(&self, _route_id: &str) {}
89}
90
91#[cfg(test)]
92mod tests {
93    use super::*;
94
95    #[test]
96    fn component_context_health_default_is_noop() {
97        let ctx = NoOpComponentContext;
98        let h = ctx.health();
99        // Must not panic.
100        h.force_unhealthy_for_route("any", "any", "any");
101    }
102}