Skip to main content

reifydb_runtime/
shutdown.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::fmt;
5
6use reifydb_value::{
7	Result,
8	error::{Diagnostic, Error},
9	fragment::Fragment,
10};
11
12pub trait Shutdown {
13	fn shutdown(&self) -> Result<()>;
14}
15
16pub fn shutdown_failed(subsystem: impl fmt::Display, reason: impl fmt::Display) -> Diagnostic {
17	Diagnostic {
18		code: "SUB_004".to_string(),
19		rql: None,
20		message: format!("{} subsystem shutdown failed: {}", subsystem, reason),
21		column: None,
22		fragment: Fragment::None,
23		label: None,
24		help: None,
25		notes: vec![],
26		cause: None,
27		operator_chain: None,
28	}
29}
30
31pub struct ShutdownErrors {
32	owner: &'static str,
33	failed: Vec<String>,
34}
35
36impl ShutdownErrors {
37	pub fn new(owner: &'static str) -> Self {
38		Self {
39			owner,
40			failed: Vec::new(),
41		}
42	}
43
44	pub fn step(&mut self, part: &'static str, result: Result<()>) {
45		let Err(err) = result else {
46			return;
47		};
48		let diagnostic = err.diagnostic();
49		if diagnostic.code == "SUB_004" {
50			self.failed.extend(diagnostic.notes.into_iter().map(|note| format!("{part}/{note}")));
51		} else {
52			self.failed.push(format!("{part}: {}", diagnostic.message));
53		}
54	}
55
56	pub fn fail(&mut self, part: &'static str, reason: impl fmt::Display) {
57		self.failed.push(format!("{part}: {reason}"));
58	}
59
60	pub fn finish(self) -> Result<()> {
61		if self.failed.is_empty() {
62			return Ok(());
63		}
64		let reason = format!("{} parts failed", self.failed.len());
65		Err(Error(Box::new(Diagnostic {
66			notes: self.failed,
67			..shutdown_failed(self.owner, reason)
68		})))
69	}
70}