2025-03-24 16:47:42 +01:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
use std::time::Duration;
|
|
|
|
|
use tokio::time;
|
|
|
|
|
use tracing::{debug, error, info, instrument};
|
|
|
|
|
|
|
|
|
|
use crate::common::errors::Result;
|
|
|
|
|
use crate::domain::repositories::trash_repository::TrashRepository;
|
|
|
|
|
use crate::application::ports::trash_ports::TrashUseCase;
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
/// Service for automatic cleanup of expired items in the trash
|
2025-03-24 16:47:42 +01:00
|
|
|
pub struct TrashCleanupService {
|
|
|
|
|
trash_service: Arc<dyn TrashUseCase>,
|
|
|
|
|
trash_repository: Arc<dyn TrashRepository>,
|
|
|
|
|
cleanup_interval_hours: u64,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl TrashCleanupService {
|
|
|
|
|
pub fn new(
|
|
|
|
|
trash_service: Arc<dyn TrashUseCase>,
|
|
|
|
|
trash_repository: Arc<dyn TrashRepository>,
|
|
|
|
|
cleanup_interval_hours: u64,
|
|
|
|
|
) -> Self {
|
|
|
|
|
Self {
|
|
|
|
|
trash_service,
|
|
|
|
|
trash_repository,
|
2026-02-12 09:41:25 +01:00
|
|
|
cleanup_interval_hours: cleanup_interval_hours.max(1), // Minimum 1 hour
|
2025-03-24 16:47:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
/// Starts the periodic cleanup job
|
2025-03-24 16:47:42 +01:00
|
|
|
#[instrument(skip(self))]
|
|
|
|
|
pub async fn start_cleanup_job(&self) {
|
|
|
|
|
let trash_repository = self.trash_repository.clone();
|
|
|
|
|
let trash_service = self.trash_service.clone();
|
|
|
|
|
let interval_hours = self.cleanup_interval_hours;
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
info!("Starting trash cleanup job with interval of {} hours", interval_hours);
|
2025-03-24 16:47:42 +01:00
|
|
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
|
let interval_duration = Duration::from_secs(interval_hours * 60 * 60);
|
|
|
|
|
let mut interval = time::interval(interval_duration);
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
// First immediate execution
|
2025-03-24 16:47:42 +01:00
|
|
|
Self::cleanup_expired_items(trash_repository.clone(), trash_service.clone()).await
|
2026-02-12 09:41:25 +01:00
|
|
|
.unwrap_or_else(|e| error!("Error in initial trash cleanup: {:?}", e));
|
2025-03-24 16:47:42 +01:00
|
|
|
|
|
|
|
|
loop {
|
|
|
|
|
interval.tick().await;
|
2026-02-12 09:41:25 +01:00
|
|
|
debug!("Running scheduled trash cleanup task");
|
2025-03-24 16:47:42 +01:00
|
|
|
|
|
|
|
|
if let Err(e) = Self::cleanup_expired_items(
|
|
|
|
|
trash_repository.clone(),
|
|
|
|
|
trash_service.clone()
|
|
|
|
|
).await {
|
2026-02-12 09:41:25 +01:00
|
|
|
error!("Error in scheduled trash cleanup: {:?}", e);
|
2025-03-24 16:47:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
/// Cleans up expired items in the trash
|
2025-03-24 16:47:42 +01:00
|
|
|
#[instrument(skip(trash_repository, trash_service))]
|
|
|
|
|
async fn cleanup_expired_items(
|
|
|
|
|
trash_repository: Arc<dyn TrashRepository>,
|
|
|
|
|
trash_service: Arc<dyn TrashUseCase>,
|
|
|
|
|
) -> Result<()> {
|
2026-02-12 09:41:25 +01:00
|
|
|
debug!("Starting cleanup of expired items in the trash");
|
2025-03-24 16:47:42 +01:00
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
// Get all expired items
|
2025-03-24 16:47:42 +01:00
|
|
|
let expired_items = trash_repository.get_expired_items().await?;
|
|
|
|
|
|
|
|
|
|
if expired_items.is_empty() {
|
2026-02-12 09:41:25 +01:00
|
|
|
debug!("No expired items to clean up");
|
2025-03-24 16:47:42 +01:00
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
info!("Found {} expired items to delete", expired_items.len());
|
2025-03-24 16:47:42 +01:00
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
// Delete each expired item
|
2025-03-24 16:47:42 +01:00
|
|
|
for item in expired_items {
|
2026-02-08 13:40:23 +01:00
|
|
|
let trash_id = item.id().to_string();
|
|
|
|
|
let user_id = item.user_id().to_string();
|
2025-03-24 16:47:42 +01:00
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
debug!("Deleting expired item: id={}, user={}", trash_id, user_id);
|
2025-03-24 16:47:42 +01:00
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
// If a deletion fails, continue with the rest
|
2025-03-24 16:47:42 +01:00
|
|
|
if let Err(e) = trash_service.delete_permanently(&trash_id, &user_id).await {
|
2026-02-12 09:41:25 +01:00
|
|
|
error!("Error deleting expired item {}: {:?}", trash_id, e);
|
2025-03-24 16:47:42 +01:00
|
|
|
} else {
|
2026-02-12 09:41:25 +01:00
|
|
|
debug!("Expired item deleted successfully: {}", trash_id);
|
2025-03-24 16:47:42 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-12 09:41:25 +01:00
|
|
|
info!("Trash cleanup completed");
|
2025-03-24 16:47:42 +01:00
|
|
|
Ok(())
|
|
|
|
|
}
|
|
|
|
|
}
|