use anyhow::Result;
use bollard::container::ListContainersOptions;
use bollard::volume::ListVolumesOptions;
use bollard::Docker;
use std::collections::HashMap;
use std::time::Duration;
use tokio::time;
use tracing::info;
pub async fn run_reaper(docker: Docker) -> Result<()> {
let mut interval = time::interval(Duration::from_secs(3600)); loop {
interval.tick().await;
info!("Running garbage collection (reaper) on Docker containers and volumes...");
let mut filters = HashMap::new();
filters.insert("label", vec!["managed-by=stormchaser"]);
if let Ok(containers) = docker
.list_containers(Some(ListContainersOptions {
all: true,
filters: filters.clone(),
..Default::default()
}))
.await
{
for container in containers {
let now = chrono::Utc::now();
let created_ts = container.created.unwrap_or(0);
let created = chrono::DateTime::from_timestamp(created_ts, 0)
.unwrap_or_else(chrono::Utc::now);
let age = now - created;
if age.num_hours() >= 24 {
if let Some(id) = container.id {
info!("Reaping old container {} (age: {}h)", id, age.num_hours());
let _ = docker.stop_container(&id, None).await;
let _ = docker.remove_container(&id, None).await;
}
}
}
}
if let Ok(volumes_res) = docker
.list_volumes(Some(ListVolumesOptions {
filters: filters.clone(),
}))
.await
{
if let Some(volumes) = volumes_res.volumes {
for vol in volumes {
info!("Found managed volume: {}", vol.name);
}
}
}
}
}