mockforge_analytics/
retention.rs

1//! Data retention and cleanup service
2
3use crate::config::RetentionConfig;
4use crate::database::AnalyticsDatabase;
5use crate::error::Result;
6use std::sync::Arc;
7use tokio::time::{interval, Duration};
8use tracing::{error, info};
9
10/// Data retention service
11pub struct RetentionService {
12    db: AnalyticsDatabase,
13    config: RetentionConfig,
14}
15
16impl RetentionService {
17    /// Create a new retention service
18    pub fn new(db: AnalyticsDatabase, config: RetentionConfig) -> Self {
19        Self { db, config }
20    }
21
22    /// Start the retention service
23    pub async fn start(self: Arc<Self>) {
24        info!("Starting data retention service");
25
26        let interval_seconds = self.config.cleanup_interval_hours as u64 * 3600;
27        let mut interval = interval(Duration::from_secs(interval_seconds));
28
29        loop {
30            interval.tick().await;
31
32            if let Err(e) = self.run_cleanup().await {
33                error!("Error running data cleanup: {}", e);
34            }
35        }
36    }
37
38    /// Run cleanup for all tables
39    async fn run_cleanup(&self) -> Result<()> {
40        info!("Running analytics data cleanup");
41
42        // Cleanup minute aggregates
43        let deleted = self.db.cleanup_minute_aggregates(self.config.minute_aggregates_days).await?;
44        info!("Deleted {} old minute aggregates", deleted);
45
46        // Cleanup hour aggregates
47        let deleted = self.db.cleanup_hour_aggregates(self.config.hour_aggregates_days).await?;
48        info!("Deleted {} old hour aggregates", deleted);
49
50        // Cleanup error events
51        let deleted = self.db.cleanup_error_events(self.config.error_events_days).await?;
52        info!("Deleted {} old error events", deleted);
53
54        // Run vacuum to reclaim space
55        self.db.vacuum().await?;
56
57        info!("Data cleanup completed successfully");
58        Ok(())
59    }
60
61    /// Manually trigger cleanup (useful for testing or admin commands)
62    pub async fn trigger_cleanup(&self) -> Result<()> {
63        self.run_cleanup().await
64    }
65}
66
67#[cfg(test)]
68mod tests {
69    use super::*;
70    use std::path::Path;
71
72    #[tokio::test]
73    async fn test_retention_service_creation() {
74        let db = AnalyticsDatabase::new(Path::new(":memory:")).await.unwrap();
75        db.run_migrations().await.unwrap();
76
77        let config = RetentionConfig::default();
78        let service = RetentionService::new(db, config);
79
80        // Test manual cleanup
81        service.trigger_cleanup().await.unwrap();
82    }
83}