omni_orchestrator/app_autoscaler/
app.rs

1use std::collections::HashMap;
2use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
3use serde::{Serialize, Deserialize, Serializer, Deserializer};
4
5/// Represents an app instance managed by the autoscaler
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct AppInstance {
8    /// Unique identifier for the app instance
9    pub id: String,
10    /// Human-readable name for the app instance
11    pub name: String,
12    /// ID of the node hosting this app instance
13    pub node_id: String,
14    /// CPU cores allocated to this app instance
15    pub cpu: u32,
16    /// Memory in MB allocated to this app instance
17    pub memory: u32,
18    /// Storage in GB allocated to this app instance
19    pub storage: u32,
20    /// Current state of the app instance
21    pub state: AppInstanceState,
22    /// When the app instance was created (as milliseconds since UNIX epoch)
23    #[serde(with = "timestamp_serde")]
24    pub created_at: Instant,
25    /// Last time the app instance state was updated (as milliseconds since UNIX epoch)
26    #[serde(with = "timestamp_serde")]
27    pub updated_at: Instant,
28    /// Additional properties specific to this app instance
29    pub properties: HashMap<String, String>,
30}
31
32mod timestamp_serde {
33    use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
34    use serde::{Deserialize, Deserializer, Serializer};
35
36    pub fn serialize<S>(instant: &Instant, serializer: S) -> Result<S::Ok, S::Error>
37    where
38        S: Serializer,
39    {
40        let duration = instant.duration_since(Instant::now()) + SystemTime::now()
41            .duration_since(UNIX_EPOCH)
42            .unwrap_or(Duration::from_secs(0));
43        serializer.serialize_u64(duration.as_millis() as u64)
44    }
45
46    pub fn deserialize<'de, D>(deserializer: D) -> Result<Instant, D::Error>
47    where
48        D: Deserializer<'de>,
49    {
50        let millis = u64::deserialize(deserializer)?;
51        let duration = Duration::from_millis(millis);
52        let system_now = SystemTime::now()
53            .duration_since(UNIX_EPOCH)
54            .unwrap_or(Duration::from_secs(0));
55        Ok(Instant::now() - (system_now - duration))
56    }
57}
58
59impl AppInstance {
60    /// Create a new app instance
61    pub fn new(id: String, name: String, node_id: String, cpu: u32, memory: u32, storage: u32) -> Self {
62        let now = Instant::now();
63        Self {
64            id,
65            name,
66            node_id,
67            cpu,
68            memory,
69            storage,
70            state: AppInstanceState::Creating,
71            created_at: now,
72            updated_at: now,
73            properties: HashMap::new(),
74        }
75    }
76}
77
78/// Possible states for an app instance
79#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
80pub enum AppInstanceState {
81    /// App instance is being created
82    Creating,
83    /// App instance is running
84    Running,
85    /// App instance is stopped
86    Stopped,
87    /// App instance is being terminated
88    Terminating,
89    /// App instance has been terminated
90    Terminated,
91    /// App instance is in error state
92    Error,
93}
94
95/// Configuration for app instance creation
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct AppConfig {
98    /// CPU cores for each app instance
99    pub cpu: u32,
100    /// Memory in MB for each app instance
101    pub memory: u32,
102    /// Storage in GB for each app instance
103    pub storage: u32,
104    /// Additional configuration options
105    pub options: HashMap<String, String>,
106}
107
108impl Default for AppConfig {
109    fn default() -> Self {
110        Self {
111            cpu: 2,
112            memory: 4096, // 4 GB
113            storage: 80,  // 80 GB
114            options: HashMap::new(),
115        }
116    }
117}
118
119/// Template for creating new app instances
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct AppTemplate {
122    /// Base name for app instances created from this template
123    pub base_name: String,
124    /// App configuration
125    pub config: AppConfig,
126    /// Additional tags to apply to app instances
127    pub tags: HashMap<String, String>,
128}
129
130impl Default for AppTemplate {
131    fn default() -> Self {
132        Self {
133            base_name: "worker".to_string(),
134            config: AppConfig::default(),
135            tags: HashMap::new(),
136        }
137    }
138}