use crate::storage::StorageEngine;
use std::sync::Arc;
use tokio::time::{interval, Duration};
pub fn spawn_multipart_gc(
storage: Arc<StorageEngine>,
retention_hours: u64,
interval_secs: u64,
) -> tokio::task::JoinHandle<()> {
tokio::spawn(async move {
let mut ticker = interval(Duration::from_secs(interval_secs));
loop {
ticker.tick().await;
match storage.gc_abandoned_multipart(None, retention_hours).await {
Ok(count) => {
if count > 0 {
tracing::info!(
cleaned = count,
retention_hours,
"Multipart GC sweep completed"
);
} else {
tracing::debug!("Multipart GC sweep: no abandoned uploads found");
}
}
Err(e) => {
tracing::warn!(error = %e, "Multipart GC sweep failed");
}
}
}
})
}
pub async fn gc_sweep(
storage: &StorageEngine,
bucket: Option<&str>,
retention_hours: u64,
) -> Result<u64, crate::storage::StorageError> {
storage
.gc_abandoned_multipart(bucket, retention_hours)
.await
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_gc_sweep_empty_storage() {
let tmp = std::env::temp_dir().join(format!("rs3gw-gc-test-{}", uuid::Uuid::new_v4()));
let storage = StorageEngine::new(tmp.clone()).expect("failed to create storage engine");
let result = gc_sweep(&storage, None, 1).await;
assert!(result.is_ok());
assert_eq!(result.expect("gc_sweep failed"), 0);
let _ = tokio::fs::remove_dir_all(&tmp).await;
}
}