tutti_core/supervisor/
main.rs

1use tokio::sync::mpsc;
2use tutti_types::{Project, ProjectId};
3
4use crate::{
5    error::{Error, Result},
6    process_manager::ProcessManager,
7    supervisor::{
8        background::SupervisorBackground,
9        commands::{SupervisorCommand, SupervisorEvent},
10    },
11};
12
13#[derive(Debug)]
14pub struct Supervisor {
15    _task: tokio::task::JoinHandle<()>,
16    commands_tx: mpsc::Sender<SupervisorCommand>,
17}
18
19impl Supervisor {
20    pub fn new<P: ProcessManager + Send + Sync + 'static>(
21        process_manager: P,
22    ) -> (Self, mpsc::Receiver<SupervisorEvent>) {
23        let (commands_tx, commands_rx) = mpsc::channel::<SupervisorCommand>(100);
24        let (mut inner, output_rx) =
25            SupervisorBackground::new(process_manager, commands_tx.clone(), commands_rx);
26
27        let task = tokio::spawn(async move {
28            inner.run().await;
29        });
30
31        (
32            Self {
33                _task: task,
34                commands_tx,
35            },
36            output_rx,
37        )
38    }
39
40    /// Shutdown the supervisor.
41    ///
42    /// # Errors
43    /// Returns an error if the supervisor fails to shutdown.
44    pub async fn down(&mut self, project_id: ProjectId) -> Result<()> {
45        self.commands_tx
46            .send(SupervisorCommand::Down { project_id })
47            .await
48            .map_err(|err| Error::Internal(err.to_string()))?;
49
50        Ok(())
51    }
52
53    /// Shutdown the supervisor.
54    ///
55    /// # Errors
56    /// Returns an error if the supervisor fails to shutdown.
57    pub async fn shutdown(&mut self) -> Result<()> {
58        self.commands_tx
59            .send(SupervisorCommand::Shutdown)
60            .await
61            .map_err(|err| Error::Internal(err.to_string()))?;
62
63        Ok(())
64    }
65
66    /// Start the supervisor.
67    ///
68    /// # Errors
69    /// Returns an error if the supervisor fails to start.
70    pub async fn up(&mut self, project: Project, services: Vec<String>) -> Result<()> {
71        tracing::trace!(
72            "Received up command for project {project:?} to start services {services:?}"
73        );
74
75        let project_id = project.id.clone();
76
77        self.commands_tx
78            .send(SupervisorCommand::UpdateConfig {
79                project_id: project_id.clone(),
80                config: project,
81            })
82            .await
83            .map_err(|err| Error::Internal(err.to_string()))?;
84        self.commands_tx
85            .send(SupervisorCommand::Up {
86                project_id: project_id.clone(),
87                services,
88            })
89            .await
90            .map_err(|err| Error::Internal(err.to_string()))?;
91
92        Ok(())
93    }
94}