Skip to main content

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