integrate docker and implement state tracking for server lifecycle management
This commit is contained in:
109
src/state.rs
Normal file
109
src/state.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
use tokio::time::Instant;
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct StartupMetrics {
|
||||
pub total_startups: u32,
|
||||
pub total_duration_secs: u64,
|
||||
}
|
||||
|
||||
impl StartupMetrics {
|
||||
pub fn record_startup(&mut self, duration_secs: u64) {
|
||||
self.total_startups += 1;
|
||||
self.total_duration_secs += duration_secs;
|
||||
}
|
||||
|
||||
pub fn average_startup_time(&self) -> Option<u64> {
|
||||
if self.total_startups == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(self.total_duration_secs / self.total_startups as u64)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ServerState {
|
||||
Unknown,
|
||||
Stopped,
|
||||
Starting {
|
||||
started_at: Instant,
|
||||
},
|
||||
Running {
|
||||
rcon_connected_at: Instant,
|
||||
},
|
||||
Stopping {
|
||||
stop_requested_at: Instant,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct SharedServerState {
|
||||
state: Arc<RwLock<ServerState>>,
|
||||
metrics: Arc<RwLock<StartupMetrics>>,
|
||||
}
|
||||
|
||||
impl SharedServerState {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
state: Arc::new(RwLock::new(ServerState::Unknown)),
|
||||
metrics: Arc::new(RwLock::new(StartupMetrics::default())),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get(&self) -> ServerState {
|
||||
self.state.read().await.clone()
|
||||
}
|
||||
|
||||
pub async fn set(&self, new_state: ServerState) {
|
||||
let mut state = self.state.write().await;
|
||||
let old_state = state.clone();
|
||||
*state = new_state.clone();
|
||||
|
||||
if old_state != new_state {
|
||||
println!("State transition: {:?} -> {:?}", old_state, new_state);
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn transition_to_starting(&self) {
|
||||
self.set(ServerState::Starting {
|
||||
started_at: Instant::now(),
|
||||
}).await;
|
||||
}
|
||||
|
||||
pub async fn transition_to_running(&self) {
|
||||
self.set(ServerState::Running {
|
||||
rcon_connected_at: Instant::now(),
|
||||
}).await;
|
||||
}
|
||||
|
||||
pub async fn transition_to_stopping(&self) {
|
||||
self.set(ServerState::Stopping {
|
||||
stop_requested_at: Instant::now(),
|
||||
}).await;
|
||||
}
|
||||
|
||||
pub async fn transition_to_stopped(&self) {
|
||||
self.set(ServerState::Stopped).await;
|
||||
}
|
||||
|
||||
pub async fn record_startup_duration(&self, duration_secs: u64) {
|
||||
let mut metrics = self.metrics.write().await;
|
||||
metrics.record_startup(duration_secs);
|
||||
println!("Server startup took {}s (avg: {}s over {} startups)",
|
||||
duration_secs,
|
||||
metrics.average_startup_time().unwrap_or(0),
|
||||
metrics.total_startups);
|
||||
}
|
||||
|
||||
pub async fn get_average_startup_time(&self) -> Option<u64> {
|
||||
self.metrics.read().await.average_startup_time()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SharedServerState {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user