use std::sync::Arc;
use std::time::Duration;
use crate::db::SeenUriStore;
pub fn spawn_cleanup_task(
store: Arc<SeenUriStore>,
interval_secs: u64,
max_age_secs: u64,
) -> tokio::task::JoinHandle<()> {
tracing::info!(
"Starting cleanup task: interval={}s, max_age={}s ({}d)",
interval_secs,
max_age_secs,
max_age_secs / 86400
);
tokio::spawn(async move {
let mut interval = tokio::time::interval(Duration::from_secs(interval_secs));
interval.tick().await;
loop {
interval.tick().await;
match store.cleanup(max_age_secs) {
Ok(removed) => {
if removed > 0 {
tracing::info!("Cleaned up {} old URIs", removed);
} else {
tracing::debug!("Cleanup: no old URIs to remove");
}
}
Err(e) => {
tracing::error!("Cleanup failed: {}", e);
}
}
}
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
#[tokio::test]
async fn test_cleanup_logic() {
let store = Arc::new(SeenUriStore::open(":memory:").unwrap());
store.mark_seen("https://example.com/1").unwrap();
store.mark_seen("https://example.com/2").unwrap();
assert!(store.is_seen("https://example.com/1").unwrap());
assert!(store.is_seen("https://example.com/2").unwrap());
let removed = store.cleanup(0).unwrap();
assert_eq!(removed, 2);
assert!(!store.is_seen("https://example.com/1").unwrap());
assert!(!store.is_seen("https://example.com/2").unwrap());
}
#[tokio::test]
async fn test_cleanup_task_preserves_recent_entries() {
let store = Arc::new(SeenUriStore::open(":memory:").unwrap());
store.mark_seen("https://example.com/recent").unwrap();
let handle = spawn_cleanup_task(store.clone(), 1, 999999);
tokio::time::sleep(Duration::from_millis(50)).await;
assert!(store.is_seen("https://example.com/recent").unwrap());
handle.abort();
}
}