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