use std::time::Duration;
use tokio::process::Command;
use tokio::time::MissedTickBehavior;
use arcbox_constants::paths::{CONTAINERD_DATA_MOUNT_POINT, DOCKER_DATA_MOUNT_POINT};
use arcbox_protocol::agent::DiskTrimResponse;
use crate::rpc::RpcResponse;
const FSTRIM_INTERVAL: Duration = Duration::from_secs(3600);
const FSTRIM_MOUNTS: [&str; 2] = [DOCKER_DATA_MOUNT_POINT, CONTAINERD_DATA_MOUNT_POINT];
pub(super) async fn fstrim_loop() {
let mut interval = tokio::time::interval(FSTRIM_INTERVAL);
interval.set_missed_tick_behavior(MissedTickBehavior::Skip);
loop {
interval.tick().await;
for mount in FSTRIM_MOUNTS {
match Command::new("fstrim").arg(mount).status().await {
Ok(s) if s.success() => {
tracing::info!("fstrim {} completed", mount);
}
Ok(s) => {
tracing::warn!(
"fstrim {} exited with code {}",
mount,
s.code().unwrap_or(-1)
);
}
Err(e) => {
tracing::warn!("fstrim {} failed: {}", mount, e);
}
}
}
}
}
async fn run_fstrim_now() -> String {
let mut results = Vec::new();
for mount in FSTRIM_MOUNTS {
match Command::new("fstrim").arg("-v").arg(mount).output().await {
Ok(output) if output.status.success() => {
let msg = String::from_utf8_lossy(&output.stdout);
results.push(format!("{}: {}", mount, msg.trim()));
}
Ok(output) => {
let msg = String::from_utf8_lossy(&output.stderr);
results.push(format!("{}: failed ({})", mount, msg.trim()));
}
Err(e) => {
results.push(format!("{}: error ({})", mount, e));
}
}
}
results.join("; ")
}
pub(super) async fn handle_disk_trim() -> RpcResponse {
let result = run_fstrim_now().await;
RpcResponse::DiskTrim(DiskTrimResponse { result })
}