Files
compost/src/stack.rs

90 lines
2.8 KiB
Rust

use crate::docker;
use crate::process::{self, ProcInfo};
use std::collections::HashMap;
use std::time::Duration;
use tokio::sync::mpsc;
use tokio::task;
use tokio::time::sleep;
#[derive(Clone, Copy, Default, Debug, PartialEq)]
pub struct StackInfo {
pub containers: u32,
pub running_containers: u32,
pub stopped_containers: u32,
pub process_count: u32,
pub cpu_percent: f64,
pub memory_usage: usize,
pub memory_percent: f64,
}
pub fn spawn_monitor(stack: docker::Stack) -> mpsc::Receiver<StackInfo> {
let (tx, rx) = mpsc::channel(64);
task::spawn(monitor_proc(tx, stack));
rx
}
async fn monitor_proc(tx: mpsc::Sender<StackInfo>, stack: docker::Stack) -> anyhow::Result<()> {
let mut proc_monitors: HashMap<u32, mpsc::Receiver<ProcInfo>> = HashMap::new();
let mut processes = HashMap::<u32, ProcInfo>::new();
let mut last_stack_info = StackInfo::default();
loop {
let mut stack_info = StackInfo::default();
let containers = docker::list_containers(&stack).await?;
stack_info.containers = containers.len() as u32;
stack_info.running_containers = containers.iter().filter(|c| c.is_running()).count() as u32;
stack_info.stopped_containers = stack_info.containers - stack_info.running_containers;
processes.clear();
for container in &containers {
for process in docker::list_processes(&stack, container).await? {
processes.insert(process.pid, Default::default());
if !proc_monitors.contains_key(&process.pid) {
proc_monitors.insert(process.pid, process::spawn_monitor(process.pid));
}
}
}
proc_monitors.retain(|&pid, monitor| {
if !processes.contains_key(&pid) {
return false;
}
match monitor.try_recv() {
Ok(info) => {
processes.insert(pid, info);
true
}
Err(mpsc::error::TryRecvError::Empty) => true,
Err(_) => false,
}
});
let memory_usage = processes.values().map(|p| p.memory_usage).sum();
let host_memory = (1usize << 20) * 16; // 10 GiB // TODO
stack_info = StackInfo {
process_count: processes.len() as u32,
memory_usage,
memory_percent: memory_usage as f64 / host_memory as f64,
cpu_percent: processes
.values()
.map(|p| p.cpu_percent)
.sum::<f64>()
.max(0.0),
..stack_info
};
if stack_info != last_stack_info {
last_stack_info = stack_info;
tx.send(stack_info).await?;
}
sleep(Duration::from_secs(1)).await;
}
}