1use std::sync::Arc;
2use std::time::Instant;
3
4use log::{debug, info, warn};
5
6use crate::context::context::Context;
7use crate::core::Error;
8use crate::core::runner::Runner;
9
10pub struct App {
11 context: Arc<Context>,
12}
13
14impl Default for App {
15 fn default() -> Self {
16 App {
17 context: Arc::new(Context::new("root")),
18 }
19 }
20}
21
22impl App {
23 pub fn get_context(&self) -> &Context {
24 &self.context
25 }
26
27 pub fn add_context(&self, context: Context) {
28 self.context.add_context(context);
29 }
30
31 pub async fn exec(&self) -> Result<(), Error> {
32 let timer = Instant::now();
33
34 info!("starting application");
35 self.context.init_contexts()?;
36
37 let mut runners = self.context.get_beans::<dyn Runner + Send + Sync>()?;
38 debug!("starting {} runners", runners.len());
39
40 let mut handles = Vec::new();
41 while let Some(r) = runners.pop() {
42 let runner = r.clone();
43 let name = runner.name().to_string();
44
45 debug!("starting runner {}", r.name());
46 handles.push(tokio::spawn(async move {
47 let result = runner.run().await;
48 (name, result)
49 }));
50 debug!("runner {} has been started in {} micros", r.name(), timer.elapsed().as_micros());
51 }
52 info!("started in {} micros", timer.elapsed().as_micros());
53
54 let mut errors = Vec::new();
55 while let Some(runner_result) = handles.pop() {
56 let (name, result) = runner_result.await.map_err(|_| {
57 Error::from("failed to start runner")
58 })?;
59
60 if let Err(error) = result {
61 warn!("runner {} has been finished with error: {}", &name, &error);
62 errors.push(error);
63 }
64 }
65
66 info!("application finished {} micros", timer.elapsed().as_micros());
67 if errors.is_empty() {
68 Ok(())
69 } else {
70 Err(Error::from(errors.join("\n")))
71 }
72 }
73}