use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InfrastructureRecommendation {
pub metric_name: String,
pub current_value: f64,
pub target_value: f64,
pub recommended_action: String,
pub urgency: String,
}
#[derive(Debug, Default)]
pub struct DevOpsAgent;
impl DevOpsAgent {
pub fn new() -> Self {
Self
}
pub fn analyze_telemetry(
&self,
tokio_latency_us: u64,
memory_rss_bytes: u64,
db_pool_active_connections: u32,
db_pool_max_connections: u32,
) -> Vec<InfrastructureRecommendation> {
let mut recommendations = Vec::new();
if tokio_latency_us > 10_000 {
recommendations.push(InfrastructureRecommendation {
metric_name: "tokio_tick_latency_us".to_string(),
current_value: tokio_latency_us as f64,
target_value: 1_000.0,
recommended_action: "Increase Tokio worker threads or offload CPU-bound blocking tasks to tokio::task::spawn_blocking".to_string(),
urgency: "HIGH".to_string(),
});
}
let memory_mb = memory_rss_bytes as f64 / (1024.0 * 1024.0);
if memory_mb > 500.0 {
recommendations.push(InfrastructureRecommendation {
metric_name: "memory_rss_mb".to_string(),
current_value: memory_mb,
target_value: 256.0,
recommended_action: "Audit response payload buffer allocations or enable Brotli asset compression level 11".to_string(),
urgency: "MEDIUM".to_string(),
});
}
if db_pool_max_connections > 0 {
let pool_utilization =
db_pool_active_connections as f64 / db_pool_max_connections as f64;
if pool_utilization > 0.85 {
recommendations.push(InfrastructureRecommendation {
metric_name: "db_pool_utilization".to_string(),
current_value: pool_utilization * 100.0,
target_value: 60.0,
recommended_action: format!(
"Scale SQLx connection pool max_connections from {} to {}",
db_pool_max_connections,
db_pool_max_connections * 2
),
urgency: "HIGH".to_string(),
});
}
}
recommendations
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_devops_agent_recommendations() {
let agent = DevOpsAgent::new();
let recs_clean = agent.analyze_telemetry(10_000, 500 * 1024 * 1024, 17, 20);
assert_eq!(recs_clean.len(), 0);
let recs = agent.analyze_telemetry(15_000, 100 * 1024 * 1024, 5, 20);
assert_eq!(recs.len(), 1);
assert_eq!(recs[0].metric_name, "tokio_tick_latency_us");
let recs_mem = agent.analyze_telemetry(500, 600 * 1024 * 1024, 5, 20);
assert_eq!(recs_mem.len(), 1);
assert_eq!(recs_mem[0].metric_name, "memory_rss_mb");
let recs_db = agent.analyze_telemetry(500, 100 * 1024 * 1024, 18, 20);
assert_eq!(recs_db.len(), 1);
assert_eq!(recs_db[0].metric_name, "db_pool_utilization");
}
}