1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct InfrastructureRecommendation {
6 pub metric_name: String,
8 pub current_value: f64,
10 pub target_value: f64,
12 pub recommended_action: String,
14 pub urgency: String,
16}
17
18#[derive(Debug, Default)]
20pub struct DevOpsAgent;
21
22impl DevOpsAgent {
23 pub fn new() -> Self {
25 Self
26 }
27
28 pub fn analyze_telemetry(
30 &self,
31 tokio_latency_us: u64,
32 memory_rss_bytes: u64,
33 db_pool_active_connections: u32,
34 db_pool_max_connections: u32,
35 ) -> Vec<InfrastructureRecommendation> {
36 let mut recommendations = Vec::new();
37
38 if tokio_latency_us > 10_000 {
40 recommendations.push(InfrastructureRecommendation {
41 metric_name: "tokio_tick_latency_us".to_string(),
42 current_value: tokio_latency_us as f64,
43 target_value: 1_000.0,
44 recommended_action: "Increase Tokio worker threads or offload CPU-bound blocking tasks to tokio::task::spawn_blocking".to_string(),
45 urgency: "HIGH".to_string(),
46 });
47 }
48
49 let memory_mb = memory_rss_bytes as f64 / (1024.0 * 1024.0);
51 if memory_mb > 500.0 {
52 recommendations.push(InfrastructureRecommendation {
53 metric_name: "memory_rss_mb".to_string(),
54 current_value: memory_mb,
55 target_value: 256.0,
56 recommended_action: "Audit response payload buffer allocations or enable Brotli asset compression level 11".to_string(),
57 urgency: "MEDIUM".to_string(),
58 });
59 }
60
61 if db_pool_max_connections > 0 {
63 let pool_utilization =
64 db_pool_active_connections as f64 / db_pool_max_connections as f64;
65 if pool_utilization > 0.85 {
66 recommendations.push(InfrastructureRecommendation {
67 metric_name: "db_pool_utilization".to_string(),
68 current_value: pool_utilization * 100.0,
69 target_value: 60.0,
70 recommended_action: format!(
71 "Scale SQLx connection pool max_connections from {} to {}",
72 db_pool_max_connections,
73 db_pool_max_connections * 2
74 ),
75 urgency: "HIGH".to_string(),
76 });
77 }
78 }
79
80 recommendations
81 }
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_devops_agent_recommendations() {
90 let agent = DevOpsAgent::new();
91
92 let recs_clean = agent.analyze_telemetry(10_000, 500 * 1024 * 1024, 17, 20);
94 assert_eq!(recs_clean.len(), 0);
95
96 let recs = agent.analyze_telemetry(15_000, 100 * 1024 * 1024, 5, 20);
98 assert_eq!(recs.len(), 1);
99 assert_eq!(recs[0].metric_name, "tokio_tick_latency_us");
100
101 let recs_mem = agent.analyze_telemetry(500, 600 * 1024 * 1024, 5, 20);
103 assert_eq!(recs_mem.len(), 1);
104 assert_eq!(recs_mem[0].metric_name, "memory_rss_mb");
105
106 let recs_db = agent.analyze_telemetry(500, 100 * 1024 * 1024, 18, 20);
108 assert_eq!(recs_db.len(), 1);
109 assert_eq!(recs_db[0].metric_name, "db_pool_utilization");
110 }
111}