harmos_runtime/operations/manager/
residents.rs1use std::collections::BTreeMap;
22use std::sync::Arc;
23use tokio::sync::watch;
25use super::super::caller::Identity;
27use super::super::handler::Outcome;
28use super::super::resident::{self, Activation, Definition, Key, Kind, Lease, Snapshot};
29use super::super::{OperationDeclaration, OperationInstance, OperationInstanceId, Response};
30use super::OperationManager;
31use crate::observers::{Backend, ObserverBackend, ObserverRegistration};
32use crate::services::{Resident, ServiceDefinition};
33use crate::{Application, Result};
34
35impl OperationManager {
50 pub fn register_observer<B: ObserverBackend>(&self, backend: B) -> Result<()> {
53 let definition = backend.definition()?;
54 self.resident.register(Definition::Observer(definition), Arc::new(Backend(backend)), None, false, false)
55 }
56
57 pub fn stage_observers<B: ObserverBackend>(
60 &self, resources: &Arc<B::Resources>, backends: impl IntoIterator<Item = B>,
61 ) -> Result<ObserverRegistration> {
62 self.stage_scoped(
63 resources,
64 backends,
65 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
66 None,
67 )
68 }
69
70 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
71 pub fn stage_plugin_observers<B: ObserverBackend>(
72 &self, resources: &Arc<B::Resources>, plugin: &crate::plugin::PluginScope, backends: impl IntoIterator<Item = B>,
73 ) -> Result<ObserverRegistration> {
74 self.stage_scoped(resources, backends, Some(plugin.clone()))
75 }
76
77 fn stage_scoped<B: ObserverBackend>(
78 &self, resources: &Arc<B::Resources>, backends: impl IntoIterator<Item = B>,
79 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))] plugin: Option<crate::plugin::PluginScope>,
80 ) -> Result<ObserverRegistration> {
81 let scope = self.resident.scope(Arc::clone(resources))?;
82 let entries = backends
83 .into_iter()
84 .map(|backend| {
85 let definition = backend.definition()?;
86 let runner: Arc<dyn resident::Runner> = Arc::new(Backend(backend));
87 Ok((Definition::Observer(definition), runner))
88 })
89 .collect::<Result<Vec<_>>>()?;
90 self.resident.stage(
91 &scope,
92 entries,
93 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
94 plugin,
95 )
96 }
97
98 #[cfg(feature = "plugin-sidecar")]
101 pub fn register_native_observer<R, H, F>(&self, instance: harmos_sidecar::Instance<R, H>, factory: F) -> Result<()>
102 where
103 R: Send + Sync + 'static,
104 H: Send + Sync + 'static,
105 F: Fn(Arc<R>) -> H + Send + Sync + 'static,
106 {
107 self.register_observer(crate::observers::Native { instance, factory: Arc::new(factory) })
108 }
109
110 #[cfg(feature = "plugin-sidecar")]
111 pub fn stage_native_observers<R, H, F>(
112 &self, resources: &Arc<R>, instances: impl IntoIterator<Item = harmos_sidecar::Instance<R, H>>, factory: F,
113 ) -> Result<ObserverRegistration>
114 where
115 R: Send + Sync + 'static,
116 H: Send + Sync + 'static,
117 F: Fn(Arc<R>) -> H + Send + Sync + 'static,
118 {
119 let factory = Arc::new(factory);
120 self.stage_observers(
121 resources,
122 instances.into_iter().map(|instance| crate::observers::Native { instance, factory: Arc::clone(&factory) }),
123 )
124 }
125
126 pub fn register_service<A, R, F, T>(&self, definition: ServiceDefinition, factory: F) -> Result<()>
129 where
130 A: Application,
131 R: Send + Sync + 'static,
132 F: Fn(Arc<R>) -> T + Send + Sync + 'static,
133 T: Resident<A>,
134 {
135 let runner = crate::services::Typed::new(definition.clone(), factory);
136 self.resident.register(Definition::Service(definition), Arc::new(runner), None, false, false)
137 }
138
139 pub(crate) fn start_service<A: Application>(&self, service: crate::services::Once<A>, internal: bool, reserved: bool) -> Result<Lease> {
142 let definition = Definition::Service(service.definition());
143 self.resident.start_once(self, definition, Arc::new(service), internal, reserved)
144 }
145
146 pub(crate) fn hold_resident(&self, lease: Lease) {
147 self.resident.hold(lease);
148 }
149
150 pub(crate) fn resident_instance<O: OperationDeclaration<Response = ()>>(lease: Lease) -> OperationInstance<O> {
151 let id = lease.id();
152 let generation = lease.generation();
153 let control = lease.lifecycle();
154 let settled = lease.settlement();
155 OperationInstance {
156 id,
157 generation,
158 outcome: Outcome::Resident {
159 lease: Some(lease),
160 settled: std::sync::Mutex::new(Box::pin(async move { settled.await.map(|()| Response::new(())) })),
161 },
162 control,
163 released: false,
164 }
165 }
166
167 pub(in crate::operations) async fn activate_resident<O, R>(
168 &self, id: &str, resources: Arc<R>, holder: Identity,
169 ) -> Result<OperationInstance<O>>
170 where
171 O: OperationDeclaration<Response = ()>,
172 R: Send + Sync + 'static,
173 {
174 let scope = self.resident.scope(resources)?;
175 let lease = self.resident.activate(self, id, &scope, std::any::TypeId::of::<R>(), holder, false).await?;
176 Ok(Self::resident_instance(lease))
177 }
178
179 pub async fn submit_with_resources_at<R: Send + Sync + 'static>(
182 &self, id: &str, resources: Arc<R>,
183 ) -> Result<OperationInstance<Activation>> {
184 self.activate_resident::<Activation, R>(id, resources, Identity::Host).await
185 }
186
187 pub async fn submit_resident(&self, id: &str) -> Result<OperationInstance<Activation>> {
189 let root = self.resident.root();
190 let lease = self.resident.activate(self, id, &root, std::any::TypeId::of::<()>(), Identity::Host, false).await?;
191 Ok(Self::resident_instance(lease))
192 }
193
194 pub fn resident_definition(&self, id: &str) -> Option<Definition> {
195 self.resident.definition(id)
196 }
197
198 pub fn resident_definitions(&self) -> Vec<Definition> {
199 self.resident.definitions()
200 }
201
202 pub fn resident(&self, key: &Key) -> Option<Snapshot> {
203 self.resident.status(key)
204 }
205
206 pub fn residents(&self) -> BTreeMap<Key, Snapshot> {
207 self.resident.statuses()
208 }
209
210 pub fn watch_residents(&self) -> watch::Receiver<BTreeMap<Key, Snapshot>> {
211 self.resident.subscribe()
212 }
213
214 pub fn resident_key(&self, instance: OperationInstanceId) -> Option<Key> {
216 self.resident.statuses().into_iter().find_map(|(key, snapshot)| (snapshot.instance == instance).then_some(key))
217 }
218
219 pub fn root_resources(&self) -> Arc<()> {
221 self.resident.root_resources()
222 }
223
224 pub async fn retire_resources<R: Send + Sync + 'static>(&self, resources: &Arc<R>) -> Result<()> {
227 let Some(scope) = self.resident.scope_of(resources) else {
228 return Ok(());
229 };
230 self.resident.retire_scope(&scope).await?.into_outcome().map_err(|source| crate::Error::TaskFailed { domain: "resident", source })
231 }
232
233 #[cfg(feature = "plugin-sidecar")]
234 pub(crate) async fn retire_scope_of<R: Send + Sync + 'static>(&self, resources: &Arc<R>) -> Result<Option<resident::Retirement>> {
235 let Some(scope) = self.resident.scope_of(resources) else {
236 return Ok(None);
237 };
238 self.resident.retire_scope(&scope).await.map(Some)
239 }
240
241 pub async fn unregister_resident(&self, id: &str) -> Result<()> {
242 self.resident.unregister(id).await
243 }
244
245 pub(crate) fn resident_identity(&self) -> Arc<()> {
246 self.resident.identity()
247 }
248
249 pub(crate) fn handles<A: Application>(&self) -> crate::services::Handles<A> {
250 self.instances.handles_of::<A>().clone()
251 }
252
253 pub(crate) fn close_resident_admission(&self) {
254 self.resident.close_admission();
255 }
256
257 pub async fn stop_observers(&self) -> Result<()> {
260 self.resident.stop_kind(Kind::Observer).await
261 }
262
263 pub(crate) async fn shutdown_observers(&self) -> Result<()> {
264 self.resident.shutdown_observers().await
265 }
266
267 pub(crate) async fn shutdown_application_services(&self) -> Result<()> {
268 self.resident.shutdown_application().await
269 }
270
271 pub async fn shutdown_residents(&self) -> Result<()> {
274 self.resident.shutdown().await
275 }
276
277 pub(crate) fn observer_cleanup_pending(&self) -> bool {
278 self.resident.cleanup_pending(|kind, _| kind == Kind::Observer)
279 }
280
281 pub(crate) fn service_cleanup_pending(&self, infrastructure: bool) -> bool {
282 self.resident.cleanup_pending(|kind, internal| kind == Kind::Service && (infrastructure || !internal))
283 }
284}
285
286