1use crate::ShutdownToken;
15use async_trait::async_trait;
16use nagisa_types::error::{Error, Result};
17use std::any::{Any, TypeId};
18use std::collections::HashMap;
19use std::sync::{Arc, RwLock};
20use tokio::task::JoinSet;
21
22#[derive(Clone, Default)]
26pub struct ServiceBus {
27 inner: Arc<RwLock<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>>,
28}
29
30impl ServiceBus {
31 pub fn new() -> Self {
33 Self::default()
34 }
35
36 pub fn insert<T: Send + Sync + 'static>(&self, value: T) {
39 let mut map = self.inner.write().unwrap_or_else(|e| e.into_inner());
40 map.insert(TypeId::of::<T>(), Arc::new(value));
41 }
42
43 pub fn get<T: Send + Sync + 'static>(&self) -> Option<Arc<T>> {
46 let map = self.inner.read().unwrap_or_else(|e| e.into_inner());
47 map.get(&TypeId::of::<T>()).and_then(|v| Arc::clone(v).downcast::<T>().ok())
48 }
49}
50
51#[async_trait]
73pub trait Service: Send + Sync + 'static {
74 fn id(&self) -> &'static str;
76
77 fn deps(&self) -> &'static [&'static str] {
79 &[]
80 }
81
82 async fn prepare(&self, bus: &ServiceBus) -> Result<()> {
84 let _ = bus;
85 Ok(())
86 }
87
88 async fn run(self: Arc<Self>, bus: ServiceBus, shutdown: ShutdownToken) -> Result<()> {
91 let _ = (bus, shutdown);
92 Ok(())
93 }
94
95 async fn cleanup(&self, bus: &ServiceBus) -> Result<()> {
97 let _ = bus;
98 Ok(())
99 }
100}
101
102#[derive(Default)]
104pub struct Supervisor {
105 services: Vec<Arc<dyn Service>>,
106 optional: Vec<bool>,
110 bus: ServiceBus,
111}
112
113impl Supervisor {
114 pub fn new() -> Self {
116 Self::default()
117 }
118
119 #[allow(clippy::should_implement_trait)]
123 pub fn add(mut self, service: Arc<dyn Service>) -> Self {
124 self.services.push(service);
125 self.optional.push(false);
126 self
127 }
128
129 pub fn add_optional(mut self, service: Arc<dyn Service>) -> Self {
135 self.services.push(service);
136 self.optional.push(true);
137 self
138 }
139
140 pub fn bus(&self) -> ServiceBus {
142 self.bus.clone()
143 }
144
145 pub async fn run(self, shutdown: ShutdownToken) -> Result<()> {
155 let Supervisor { services, optional, bus } = self;
156
157 let order = toposort(&services)?;
159
160 let mut prepared: Vec<usize> = Vec::with_capacity(order.len());
164 for &idx in &order {
165 match services[idx].prepare(&bus).await {
166 Ok(()) => prepared.push(idx),
167 Err(e) if optional[idx] => {
168 tracing::warn!(service = services[idx].id(), error = %e, "可选服务 prepare 失败;已跳过");
169 }
170 Err(e) => {
171 tracing::error!(service = services[idx].id(), error = %e, "必选服务 prepare 失败,清理已就绪者");
172 cleanup_reverse(&services, &prepared, &bus).await;
173 return Err(e);
174 }
175 }
176 }
177
178 let local = shutdown.child_token();
180 let mut set: JoinSet<(usize, Result<()>)> = JoinSet::new();
181 for &idx in &prepared {
182 let svc = Arc::clone(&services[idx]);
183 let bus = bus.clone();
184 let child = local.child_token();
185 set.spawn(async move { (idx, svc.run(bus, child).await) });
186 }
187
188 let mut run_result: Result<()> = Ok(());
191 loop {
192 tokio::select! {
193 biased;
194 _ = shutdown.cancelled() => break,
195 joined = set.join_next() => {
196 match joined {
197 None => break,
198 Some(Ok((_idx, Ok(())))) => continue,
199 Some(Ok((idx, Err(e)))) if optional[idx] => {
200 tracing::warn!(service = services[idx].id(), error = %e, "可选服务 run 出错;已隔离,不影响其余");
201 continue;
202 }
203 Some(Ok((idx, Err(e)))) => {
204 tracing::error!(service = services[idx].id(), error = %e, "必选服务 run 出错,收束");
205 run_result = Err(e);
206 break;
207 }
208 Some(Err(join_err)) => {
209 tracing::error!(error = %join_err, "服务 run 任务 panic,收束");
210 run_result = Err(internal_err(format!("服务 run 任务 panic:{join_err}")));
211 break;
212 }
213 }
214 }
215 }
216 }
217
218 local.cancel();
220 set.shutdown().await;
221 cleanup_reverse(&services, &prepared, &bus).await;
222
223 run_result
224 }
225}
226
227async fn cleanup_reverse(services: &[Arc<dyn Service>], indices: &[usize], bus: &ServiceBus) {
230 for &idx in indices.iter().rev() {
231 if let Err(e) = services[idx].cleanup(bus).await {
232 tracing::error!(service = services[idx].id(), error = %e, "服务清理失败");
233 }
234 }
235}
236
237fn toposort(services: &[Arc<dyn Service>]) -> Result<Vec<usize>> {
241 let mut index: HashMap<&'static str, usize> = HashMap::with_capacity(services.len());
243 for (i, svc) in services.iter().enumerate() {
244 if index.insert(svc.id(), i).is_some() {
245 return Err(internal_err(format!("duplicate service id `{}`", svc.id())));
246 }
247 }
248
249 let n = services.len();
251 let mut dependents: Vec<Vec<usize>> = vec![Vec::new(); n];
252 let mut indegree: Vec<usize> = vec![0usize; n];
253 for (i, svc) in services.iter().enumerate() {
254 for dep in svc.deps() {
255 let Some(&d) = index.get(dep) else {
256 return Err(internal_err(format!("service `{}` depends on unknown service `{dep}`", svc.id())));
257 };
258 dependents[d].push(i);
259 indegree[i] += 1;
260 }
261 }
262
263 let mut queue: std::collections::VecDeque<usize> = (0..n).filter(|&i| indegree[i] == 0).collect();
265 let mut order: Vec<usize> = Vec::with_capacity(n);
266 while let Some(node) = queue.pop_front() {
267 order.push(node);
268 for &m in &dependents[node] {
269 indegree[m] -= 1;
270 if indegree[m] == 0 {
271 queue.push_back(m);
272 }
273 }
274 }
275
276 if order.len() != n {
277 let cyclic: Vec<&str> = (0..n).filter(|&i| indegree[i] > 0).map(|i| services[i].id()).collect();
279 return Err(internal_err(format!("dependency cycle among services: {cyclic:?}")));
280 }
281
282 Ok(order)
283}
284
285fn internal_err(msg: String) -> Error {
290 Error::action(msg)
291}