1use std::future::Future;
18use std::num::NonZeroUsize;
19use std::pin::Pin;
20use std::sync::{Arc, Mutex, Weak};
21use super::{Attachment, Context as PluginContext, Error, Plugin};
25use crate::operations::{Contract, ExecutionContext, ServingError, WireTable};
26use harmos_domain::model::operations::lifecycle;
27
28pub type Table = Arc<Mutex<WireTable>>;
35type Transition<P> = Pin<Box<dyn Future<Output = (P, Result<(), Error<P>>, bool)> + Send>>;
36
37pub struct Owner<P: Plugin> {
40 slot: Arc<Mutex<Slot<P>>>,
41 table: Weak<Mutex<WireTable>>,
42 contracts: Arc<[Contract]>,
43 observers: Arc<[crate::inventory::observers::Declaration]>,
44 retirement: Mutex<Retirement<P>>,
45}
46
47struct LifecycleInvocation<P: Plugin> {
48 owner: Arc<Owner<P>>,
49 state: Option<State<P>>,
50 action: lifecycle::Action,
51}
52
53struct Retirement<P: Plugin> {
54 state: Option<State<P>>,
55 active: bool,
56 finished: bool,
57}
58
59struct RetirementLoan<P: Plugin> {
60 owner: Arc<Owner<P>>,
61 state: Option<State<P>>,
62 finished: bool,
63}
64
65struct Slot<P: Plugin> {
66 plugin: Option<P>,
67 phase: Phase,
68 attachment: Option<Arc<dyn Attachment<P::Context>>>,
69 generation_context: Option<[u8; 32]>,
70}
71
72struct State<P: Plugin> {
73 slot: Arc<Mutex<Slot<P>>>,
74 table: Weak<Mutex<WireTable>>,
75 plugin: Option<P>,
76 work: Option<Transition<P>>,
77 result: Option<Result<(), Error<P>>>,
78 action: lifecycle::Action,
79 delivered: bool,
80 failure_reported: bool,
81 shutdown_attempted: bool,
82 context: Option<P::Context>,
83 assignments: Vec<u8>,
84 attachment: Option<Arc<dyn Attachment<P::Context>>>,
85 generation_context: Option<[u8; 32]>,
86}
87
88#[derive(Clone, Copy, PartialEq, Eq)]
91enum Phase {
92 Empty,
93 Initializing,
94 Initialized,
95 Stopping,
96 Closed,
97}
98
99impl<P: Plugin> Owner<P> {
104 pub fn new(owner: &str, contracts: Vec<Contract>, capacity: NonZeroUsize) -> Result<(Arc<Self>, Table), Error<P>> {
105 Self::new_with_observers(owner, contracts, capacity, Vec::new())
106 }
107
108 pub fn new_with_observers(
109 assigned_owner: &str, contracts: Vec<Contract>, capacity: NonZeroUsize, observers: Vec<crate::inventory::observers::Declaration>,
110 ) -> Result<(Arc<Self>, Table), Error<P>> {
111 let definitions: Vec<_> = contracts.iter().map(|contract| contract.operation().clone()).collect();
112 crate::inventory::operations::validate(&definitions).map_err(|error| Error::Inventory(Arc::new(error)))?;
113 let mut serving = WireTable::new(assigned_owner).map_err(|error| Error::Serving(Arc::new(error)))?;
114 serving.capacity(capacity);
115 serving.provide(std::any::TypeId::of::<P::Context>());
116 serving.provide(std::any::TypeId::of::<crate::operations::Calls>());
117 let table = Arc::new(Mutex::new(serving));
118 let owner = Arc::new(Self {
119 slot: Arc::new(Mutex::new(Slot {
120 plugin: None,
121 phase: Phase::Empty,
122 attachment: None,
123 generation_context: None,
124 })),
125 table: Arc::downgrade(&table),
126 contracts: contracts.into(),
127 observers: observers.into(),
128 retirement: Mutex::new(Retirement {
129 state: None,
130 active: false,
131 finished: false,
132 }),
133 });
134 Ok((owner, table))
135 }
136
137 pub async fn quiesce(&self) -> Result<(), Error<P>> {
138 let attachment = self.slot.lock().map_err(|_| Error::Poisoned)?.attachment.clone();
139 if let Some(attachment) = attachment {
140 guarded(async { attachment.quiesce().await.map_err(|error| Error::Serving(Arc::new(error))) }).await?;
141 }
142 Ok(())
143 }
144
145 pub async fn retire(self: &Arc<Self>) -> Result<(), Error<P>> {
146 let table = self.table.upgrade().ok_or(Error::Phase)?;
147 {
148 let table = table.lock().map_err(|_| Error::Poisoned)?;
149 if !table.is_settled() {
150 return Err(Error::Phase);
151 }
152 }
153 let mut loan = {
154 let mut retirement = self.retirement.lock().map_err(|_| Error::Poisoned)?;
155 if retirement.finished {
156 return Ok(());
157 }
158 if retirement.active {
159 return Err(Error::Phase);
160 }
161 let state = match retirement.state.take() {
162 Some(state) => state,
163 None => self.prepare_shutdown()?,
164 };
165 retirement.active = true;
166 RetirementLoan {
167 owner: Arc::clone(self),
168 state: Some(state),
169 finished: false,
170 }
171 };
172 loan.state.as_mut().ok_or(Error::Phase)?.finalize().await?;
173 loan.finished = true;
174 Ok(())
175 }
176
177 fn state(&self, plugin: Option<P>, action: lifecycle::Action) -> State<P> {
178 State {
179 slot: Arc::clone(&self.slot),
180 table: self.table.clone(),
181 plugin,
182 work: None,
183 result: None,
184 action,
185 delivered: false,
186 failure_reported: false,
187 shutdown_attempted: false,
188 context: None,
189 assignments: Vec::new(),
190 attachment: None,
191 generation_context: None,
192 }
193 }
194}
195
196impl<P: Plugin> Drop for RetirementLoan<P> {
197 fn drop(&mut self) {
198 let mut retirement = self.owner.retirement.lock().unwrap_or_else(|error| error.into_inner());
199 retirement.active = false;
200 retirement.finished = self.finished;
201 if !self.finished {
202 retirement.state = self.state.take();
203 }
204 }
205}
206
207impl<P: Plugin> Owner<P> {
208 fn prepare_initialize(&self, config_json: &[u8], generation_context: &[u8], assignments: &[u8]) -> Result<State<P>, Error<P>> {
209 let generation_context = if generation_context.is_empty() {
210 None
211 } else {
212 let token: [u8; 32] = generation_context.try_into().map_err(|_| Error::GenerationContext)?;
213 if token == [0; 32] {
214 return Err(Error::GenerationContext);
215 }
216 Some(token)
217 };
218 let config = crate::decode_config(config_json).map_err(|error| Error::Configuration(Arc::new(error)))?;
219 let plugin = P::prepare(config).map_err(|error| Error::Plugin(Arc::new(error)))?;
220 let mut slot = self.slot.lock().map_err(|_| Error::Poisoned)?;
221 if slot.phase != Phase::Empty {
222 return Err(Error::Phase);
223 }
224 slot.phase = Phase::Initializing;
225 let mut state = self.state(Some(plugin), lifecycle::Action::Initialize);
226 state.generation_context = generation_context;
227 state.assignments = assignments.to_vec();
228 Ok(state)
229 }
230
231 async fn initialize(&self, state: &mut State<P>, context: &P::Context) -> Result<(), Error<P>> {
232 if state.work.is_none() && state.result.is_none() {
233 context.assign_operations(&state.assignments).map_err(|error| Error::Serving(Arc::new(error)))?;
234 let mut plugin = state.plugin.take().ok_or(Error::Phase)?;
235 let context = state.generation_context.map_or_else(|| context.clone(), |token| context.with_generation(token));
236 state.work = Some(Box::pin(async move {
237 let result = guarded(async { plugin.initialize(&context).await.map_err(|error| Error::Plugin(Arc::new(error))) }).await;
238 (plugin, result, false)
239 }));
240 }
241 state.finish().await?;
242 state.result.as_ref().ok_or(Error::Phase)?.clone()?;
243 if state.delivered {
244 return Ok(());
245 }
246 let inventory = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
247 let plugin = state.plugin.as_ref().ok_or(Error::Phase)?;
248 state.attachment = plugin.attachment();
249 if let Some(attachment) = &state.attachment {
250 let resources: Arc<dyn std::any::Any + Send + Sync> = plugin.resources();
251 if !Arc::ptr_eq(&resources, &attachment.resources()) {
252 return Err(Error::Serving(Arc::new(ServingError::Catalog)));
253 }
254 }
255 let actual = state.attachment.as_ref().map_or_else(Vec::new, |attachment| attachment.observers());
256 if actual.as_slice() != self.observers.as_ref() {
257 return Err(Error::Serving(Arc::new(ServingError::Catalog)));
258 }
259 Ok(())
260 }))
261 .map_err(|_| Error::Panicked)
262 .and_then(|result| result);
263 if let Err(error) = inventory {
264 state.result = Some(Err(error.clone()));
265 return Err(error);
266 }
267 let attachment = state.attachment.clone();
268 let table = self.table.upgrade().ok_or(Error::Phase)?;
269 let binding = {
270 let mut table = table.lock().map_err(|_| Error::Poisoned)?;
271 let plugin = state.plugin.as_ref().ok_or(Error::Phase)?;
272 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
273 plugin
274 .bind_operations(&mut table)
275 .and_then(|()| table.validate_contracts(&self.contracts))
276 .and_then(|()| table.validate_callees(&state.assignments))
277 }))
278 .map_err(|_| Error::Panicked)
279 .and_then(|result| result.map_err(|error| Error::Serving(Arc::new(error))))
280 };
281 if let Err(error) = binding {
282 state.result = Some(Err(error.clone()));
283 return Err(error);
284 }
285 let mut slot = self.slot.lock().map_err(|_| Error::Poisoned)?;
286 slot.plugin = state.plugin.take();
287 slot.attachment = attachment;
288 slot.generation_context = state.generation_context;
289 slot.phase = Phase::Initialized;
290 state.delivered = true;
291 Ok(())
292 }
293
294 fn prepare_shutdown(&self) -> Result<State<P>, Error<P>> {
295 let mut slot = self.slot.lock().map_err(|_| Error::Poisoned)?;
296 if matches!(slot.phase, Phase::Empty | Phase::Closed) {
297 let mut state = self.state(None, lifecycle::Action::Shutdown);
298 state.result = Some(Ok(()));
299 return Ok(state);
300 }
301 if slot.phase != Phase::Initialized {
302 return Err(Error::Phase);
303 }
304 let plugin = slot.plugin.take().ok_or(Error::Phase)?;
305 slot.phase = Phase::Stopping;
306 let mut state = self.state(Some(plugin), lifecycle::Action::Shutdown);
307 state.attachment = slot.attachment.take();
308 state.generation_context = slot.generation_context;
309 Ok(state)
310 }
311}
312
313impl<P: Plugin> crate::operations::lifecycle::PluginLifecycle for Owner<P> {
314 fn begin(self: Arc<Self>, action: lifecycle::Action) -> Box<dyn crate::operations::lifecycle::LifecycleInstance> {
315 Box::new(LifecycleInvocation { owner: self, state: None, action })
316 }
317}
318impl<P: Plugin> crate::operations::lifecycle::LifecycleInstance for LifecycleInvocation<P> {
319 fn run<'a>(
320 &'a mut self, context: ExecutionContext, config: &'a [u8], generation: &'a [u8], assignments: &'a [u8],
321 ) -> crate::operations::lifecycle::Transition<'a> {
322 Box::pin(async move {
323 let result: Result<(), Error<P>> = async {
324 match self.action {
325 lifecycle::Action::Initialize => {
326 if self.state.is_none() {
327 self.state = Some(self.owner.prepare_initialize(config, generation, assignments)?);
328 }
329 let carrier = context.resource::<P::Context>().map_err(|error| Error::Resource(Arc::new(error)))?;
330 self.owner.initialize(self.state.as_mut().ok_or(Error::Phase)?, &carrier).await
331 }
332 lifecycle::Action::Shutdown => {
333 if self.state.is_none() {
334 self.state = Some(self.owner.prepare_shutdown()?);
335 }
336 let state = self.state.as_mut().ok_or(Error::Phase)?;
337 if state.work.is_none() && state.result.is_none() {
338 let carrier = context.resource::<P::Context>().map_err(|error| Error::Resource(Arc::new(error)))?;
339 state.context =
340 Some(state.generation_context.map_or_else(|| (*carrier).clone(), |token| carrier.with_generation(token)));
341 state.start_shutdown()?;
342 }
343 state.finish().await?;
344 state.result.as_ref().ok_or(Error::Phase)?.clone()
345 }
346 }
347 }
348 .await;
349 result.map_err(Into::into)
350 })
351 }
352 fn cleanup(&mut self) -> crate::operations::lifecycle::Transition<'_> {
353 Box::pin(async {
354 match self.state.as_mut() {
355 Some(state) => state.finalize().await.map_err(Into::into),
356 None => Ok(()),
357 }
358 })
359 }
360}
361
362impl<P: Plugin> State<P> {
363 async fn finish(&mut self) -> Result<(), Error<P>> {
364 if let Some(work) = &mut self.work {
365 let (plugin, result, shutdown_attempted) = work.await;
366 self.shutdown_attempted = shutdown_attempted;
367 self.plugin = Some(plugin);
368 self.result = Some(result);
369 self.work = None;
370 }
371 Ok(())
372 }
373
374 fn start_shutdown(&mut self) -> Result<(), Error<P>> {
375 let attachment = self.attachment.clone().or_else(|| self.plugin.as_ref().and_then(Plugin::attachment));
376 let mut plugin = self.plugin.take().ok_or(Error::Phase)?;
377 let table = self.table.clone();
378 let context = self.context.clone();
379 let mut shutdown_attempted = self.shutdown_attempted;
380 self.result = None;
381 self.work = Some(Box::pin(async move {
382 let result = guarded(async {
383 if let Some(attachment) = attachment {
384 attachment.quiesce().await.map_err(|error| Error::Serving(Arc::new(error)))?;
385 }
386 let table = table.upgrade().ok_or(Error::Phase)?;
387 let settlement = {
388 let mut table = table.lock().map_err(|_| Error::Poisoned)?;
389 table.close_ordinary()
390 };
391 settlement.await.map_err(|error| Error::Serving(Arc::new(error)))?;
392 let retired = {
393 let mut table = table.lock().map_err(|_| Error::Poisoned)?;
394 table.release_ordinary().map_err(|error| Error::Serving(Arc::new(error)))?
395 };
396 drop(retired);
397 if !shutdown_attempted && let Some(context) = &context {
398 shutdown_attempted = true;
400 plugin.stop(context).await.map_err(|error| Error::Plugin(Arc::new(error)))?;
401 }
402 plugin.cleanup().await.map_err(|error| Error::Plugin(Arc::new(error)))
403 })
404 .await;
405 (plugin, result, shutdown_attempted)
406 }));
407 Ok(())
408 }
409
410 async fn finalize(&mut self) -> Result<(), Error<P>> {
411 if self.delivered {
412 return Ok(());
413 }
414 if self.action == lifecycle::Action::Initialize {
415 self.finish().await?;
416 self.action = lifecycle::Action::Shutdown;
417 self.result = None;
418 }
419 if let Some(Err(error)) = &self.result {
420 if !self.failure_reported {
421 self.failure_reported = true;
422 return Err(error.clone());
423 }
424 self.failure_reported = false;
425 self.start_shutdown()?;
426 } else if self.work.is_none() && self.result.is_none() {
427 self.start_shutdown()?;
428 }
429 self.finish().await?;
430 if let Some(Err(error)) = &self.result {
431 self.failure_reported = true;
432 return Err(error.clone());
433 }
434 self.plugin.take();
435 self.slot.lock().map_err(|_| Error::Poisoned)?.phase = Phase::Closed;
436 Ok(())
437 }
438}
439
440async fn guarded<P: Plugin>(future: impl Future<Output = Result<(), Error<P>>>) -> Result<(), Error<P>> {
446 let mut future = std::pin::pin!(future);
447 std::future::poll_fn(|context| match std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| future.as_mut().poll(context))) {
448 Ok(result) => result,
449 Err(_) => std::task::Poll::Ready(Err(Error::Panicked)),
450 })
451 .await
452}
453
454