kumo_server_common/
start.rs

1use crate::diagnostic_logging::LoggingConfig;
2use anyhow::Context;
3use config::RegisterFunc;
4use kumo_server_lifecycle::LifeCycle;
5use kumo_server_runtime::rt_spawn;
6use std::future::Future;
7use std::path::Path;
8pub struct StartConfig<'a> {
9    pub logging: LoggingConfig<'a>,
10    pub lua_funcs: &'a [RegisterFunc],
11    pub policy: &'a Path,
12}
13
14impl StartConfig<'_> {
15    pub async fn run<INIT, FINI>(
16        self,
17        init_future: INIT,
18        shutdown_future: FINI,
19    ) -> anyhow::Result<()>
20    where
21        INIT: Future<Output = anyhow::Result<()>> + Send + 'static,
22        FINI: Future<Output = ()> + Send + 'static,
23    {
24        self.logging.init()?;
25
26        rustls::crypto::aws_lc_rs::default_provider()
27            .install_default()
28            .map_err(|_| anyhow::anyhow!("failed to install default crypto provider"))?;
29
30        kumo_server_memory::setup_memory_limit().context("setup_memory_limit")?;
31
32        prometheus::register(Box::new(
33            tokio_metrics_collector::default_runtime_collector(),
34        ))
35        .context("failed to configure tokio-metrics-collector")?;
36
37        for &func in self.lua_funcs {
38            config::register(func);
39        }
40
41        config::set_policy_path(self.policy.to_path_buf())
42            .await
43            .with_context(|| format!("Error evaluating policy file {:?}", self.policy))?;
44
45        let mut life_cycle = LifeCycle::new();
46
47        let init_handle = rt_spawn("initialize", async move {
48            let mut error = None;
49            if let Err(err) = init_future.await {
50                let err = format!("{err:#}");
51                tracing::error!("problem initializing: {err}");
52                LifeCycle::request_shutdown().await;
53                error.replace(err);
54            }
55            // This log line is depended upon by the integration
56            // test harness. Do not change or remove it without
57            // making appropriate adjustments over there!
58            tracing::info!("initialization complete");
59            error
60        })?;
61
62        life_cycle.wait_for_shutdown().await;
63
64        // after waiting for those to idle out, shut down logging
65        shutdown_future.await;
66
67        tracing::info!("Shutdown completed OK!");
68
69        if let Some(error) = init_handle.await? {
70            anyhow::bail!("Initialization raised an error: {error}");
71        }
72        Ok(())
73    }
74}