harmos_runtime/operations/manager/
mod.rs1mod admission;
13mod cache;
14mod construction;
15mod entry;
16mod grants;
17mod inspection;
18mod lookup;
19mod registration;
20mod registry;
21mod retirement;
22mod shutdown;
23mod staging;
24mod submission;
25
26mod discovery;
27pub(in crate::operations) use discovery::limits;
28mod residents;
29
30use std::any::Any;
36use std::collections::{BTreeMap, VecDeque};
37use std::sync::{
38 Arc, Mutex, Weak,
39 atomic::{AtomicBool, AtomicU8, Ordering},
40};
41use tokio::sync::{OwnedSemaphorePermit, Semaphore};
43use super::admission::{Admission, Lanes};
45use super::binding::Typed;
46use super::caller::{Identity, Origin, Source};
47use super::{Context, OperationGeneration, OperationInstance, OperationInstanceId};
48
49use super::instances::Instances;
50use crate::operations::{CacheKey, Definition, OperationDeclaration};
51#[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
52use crate::plugin::PluginScope;
53use crate::supervision::executor;
54use crate::supervision::instance::Instance;
55use crate::{Error, Identifier, Result, operations::Lane, operations::Scope, state::Position};
56
57const DEFAULT_CACHE_CAPACITY: usize = 64;
60
61type CachedResponse = harmos_sdk::__private::ErasedResponse;
66
67#[derive(Clone)]
70pub struct OperationManager {
71 pub(super) registry: Arc<Registry>,
72 pub(super) instances: Arc<Instances>,
73 pub(super) lanes: Arc<Lanes>,
74 pub(super) preparation: Option<Arc<Semaphore>>,
75 pub(super) context: Arc<std::sync::OnceLock<super::CallContext>>,
76 pub(super) resident: super::resident::Registry,
77}
78
79pub(crate) struct Registry {
80 middleware: super::middleware::Configuration,
81 state: Mutex<State>,
82}
83
84#[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
85pub(crate) struct GenerationCommit<'a> {
86 _state: std::sync::MutexGuard<'a, State>,
87}
88
89struct State {
90 closing: bool,
91 entries: BTreeMap<String, BTreeMap<String, Arc<Entry>>>,
92
93 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
94 staging: Vec<std::sync::Weak<PluginScope>>,
95
96 #[cfg(feature = "grpc")]
97 grpc: BTreeMap<String, Weak<Entry>>,
98
99 #[cfg(feature = "grpc")]
100 grpc_services: std::collections::BTreeSet<String>,
101
102 cache: VecDeque<Cached>,
103 cache_capacity: usize,
104}
105
106pub(super) struct Entry {
107 owner: Identifier,
108 definition: Definition,
109 pub(super) contract: Option<crate::operations::Contract>,
110
111 #[cfg(feature = "grpc")]
112 pub(super) grpc: Option<crate::grpc::routing::Handler>,
113
114 generation: OperationGeneration,
115 lane: &'static str,
116 bounded: bool,
117
118 #[cfg(feature = "plugin-sidecar")]
120 resident: bool,
121
122 active: AtomicBool,
123 retirement: AtomicU8,
124 pending: Mutex<BTreeMap<OperationInstanceId, Arc<Instance>>>,
125 binding: Arc<dyn Any + Send + Sync>,
126
127 #[cfg(feature = "plugin-sidecar")]
128 pub(super) native_binding: Option<Arc<dyn Any + Send + Sync>>,
129
130 pub(super) wire: Option<super::wire::Dispatch>,
131
132 #[cfg(feature = "plugin-sidecar")]
133 pub(super) native: Option<Arc<super::native::Binding>>,
134
135 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
136 plugin: Option<PluginScope>,
137
138 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
139 pub(super) sdk: Option<harmos_domain::operations::lifecycle::Action>,
140}
141
142pub(super) struct Submission {
143 pub(super) submitted: tokio::time::Instant,
144 pub(super) entry: Arc<Entry>,
145 pub(super) cause: Option<Position>,
146 pub(super) preparation: Option<OwnedSemaphorePermit>,
147}
148
149#[derive(Clone, Debug)]
153pub(super) struct GrantAuthority {
154 owner: String,
155 operation: String,
156
157 #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
159 plugin: Option<(String, Option<harmos_domain::inventory::contracts::Required>)>,
160
161 external: Option<crate::operations::authorization::Authorization>,
163}
164
165struct Cached {
166 target: Weak<Entry>,
167 key: CacheKey,
168 identity: Identity,
169 response: CachedResponse,
170}
171
172#[repr(u8)]
175enum Retirement {
176 Retained,
177 Abandoned,
178 Explicit,
179 Runtime,
180}
181
182#[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
191fn grant_allowed(required: Option<&harmos_domain::inventory::contracts::Required>, grant: Option<&harmos_domain::plugin::Grant>) -> bool {
192 match grant {
193 None => true,
194 Some(grant) => required.is_some_and(|required| required.grants(grant)),
195 }
196}
197
198async fn settle(entry: &Entry) -> Result<()> {
199 let pending = entry.pending.lock().expect("operation settlement lock is healthy").clone();
200 for settled in pending.into_values() {
201 settled.settle().await.map_err(|source| Error::OperationSettlement { source })?;
202 }
203 Ok(())
204}
205
206