Skip to main content

harmos_runtime/operations/manager/
mod.rs

1/* ***
2 *
3 * Harmos
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * ***
8 */
9
10/* === Modules === */
11
12mod 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
30/* === Re-Exports === */
31
32/* === Imports === */
33
34// Standard Library Imports
35use std::any::Any;
36use std::collections::{BTreeMap, VecDeque};
37use std::sync::{
38    Arc, Mutex, Weak,
39    atomic::{AtomicBool, AtomicU8, Ordering},
40};
41// Third Party Imports
42use tokio::sync::{OwnedSemaphorePermit, Semaphore};
43// Local Imports
44use 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
57/* === Constants === */
58
59const DEFAULT_CACHE_CAPACITY: usize = 64;
60
61/* === Macros === */
62
63/* === Type Aliases === */
64
65type CachedResponse = harmos_sdk::__private::ErasedResponse;
66
67/* === Structs === */
68
69#[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    // A resident control runs until cancelled, even while its plugin retires.
119    #[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// The caller's grant authority for one admitted request. Typed bindings check
150// the request grant at admission; encoded bindings learn it from the provider
151// while preparing and check it before any attempt runs.
152#[derive(Clone, Debug)]
153pub(super) struct GrantAuthority {
154    owner: String,
155    operation: String,
156
157    // A cross-owner plugin caller and its declared requirement for this operation.
158    #[cfg(any(feature = "plugin", feature = "plugin-guest", feature = "plugin-sidecar"))]
159    plugin: Option<(String, Option<harmos_domain::inventory::contracts::Required>)>,
160
161    // External Authority Never Replaces A Plugin Caller's Own Requirement.
162    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/* === Enums === */
173
174#[repr(u8)]
175enum Retirement {
176    Retained,
177    Abandoned,
178    Explicit,
179    Runtime,
180}
181
182/* === Traits === */
183
184/* === Implementations === */
185
186/* === Public Functions === */
187
188/* === Private Functions === */
189
190#[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/* === Tests === */